I have the following code:
answer = "ABC"
flag.goto(-999, -999)
while (answer.lower != 'y' or answer.lower != 'n'):
print("You got the flag! Free play(y/n)?")
answer = input("")
if answer.lower == 'y':
pass
if answer.lower == 'n':
return None
I am trying to remove the turtle called flag, through adding it to a list then deleting it with del(testlist[0]), but it didn't work.
The output is:
You got the flag! Free play(y/n)?
y
You got the flag! Free play(y/n)?
n
You got the flag! Free play(y/n)?
Your question is confusing as the title and text ask one thing, while your example code and output show something completely different.
Let's address this question:
Is there a way to remove a turtle from the screen?
Generally turtle.hideturtle() will do what you want. The only way to dispose of turtles once created is via a screen.clear() which will destroy all of them.
(The variable turtle above needs to be set to an instance of Turtle() and the variable screen needs to be set to the singular instance of Screen().
You can get a better view on the Visibility of turtles from this documentation.
Basically, you can use either turtle.hideturtle() or turtle.ht() to make a turtle invisible. But, that does not mean that the turtle is removed, and so it still takes up memory.
You can call turtle.Screen.clear(), but that resets everything, even the things you might want to keep.
If I were in a situation where I want to delete turtles instead of hiding them because doing that over and over again will take up too much memory, I'd simply hide the turtle, and when the program need another turtle, instead of creating another one, simply unhide the hidden turtle to be used again.
Related
I'm a human trying to make an animated musical keyboard type thing so keystrokes play noises and flash pretty colors on screen that make ape brain happy. I don't want to bore you too much, that's all you really need to know to get what's going on. I think? Let me know.
Point is, I want to make the rectangle that flashes colors on keypress, fade back to gray on key release. I figured I'd do this with time, having a list of colors, iterate through them in steps back to gray setting the rectangle's fill to each with canvas.itemconfig with a like 0.01-second delay after each step. But the rectangle behaves as it did before I added the flair: key-press, cyan, key-release, gray. No animation. I tried lengthening the steps to 1 second (looong, but on purpose to see if I was just missing something; the same cyan shade stuck for 4 steps' worth of time, it should have iterated), and setting the rectangle color in the final step to an ugly magenta. The magenta stuck obviously because I never bothered changing it until another keypress cyanned it again. So why aren't the shades iterating. Also, feel free to call your band The Iterating Shades.
My code, slimmed down as much as possible:
# Blah blah blah, setup, but here's the key release handler (The part *I think* that's messing crap up).
def key_release(e):
if (e.char == 'q'):
for i in ["#0088dd", "#005e99", "#002841", "#2e2e2e"]:
canvas.itemconfig(rect, fill=i)
time.sleep(0.04)
canvas.itemconfig(kaq, fill="gray20")
elif (e.char == 'e'):
for i in ["#ff9500", "#9e5d00", "#523000", "#2e2e2e"]:
canvas.itemconfig(rect, fill=i)
time.sleep(0.04)
canvas.itemconfig(kae, fill="gray20")
time.sleep(0.04)
There. Short(?) code, and I didn't blab on too long. All's well that ends well!
Got any ideas? Fixes? Solutions? Pitchforks to throw? Let me know, with a healthy amount of thanks from me to you. I hope this glitch is just not me being silly! Have a great day! And let me know too if you need more code-- but some people are big on Minimum Reproducible Examples, so I kept it short here.
Edit. The answer below does not work. Sorry Jason, not your fault!!
My new code looks like this, but does the same thing. I had to declare a global variable called blue_step and have the method reference it because I was having trouble figuring out how to use .after() with arguments ... but that's beside the point. Anyway:
# ...
def cycle_blue():
global blue_step, rect
canvas.itemconfig(rect, fill=["#0088dd", "#005e99", "#002841", "#2e2e2e"][blue_step])
# ...
def key_release(e):
global blue_step
blue_step = 0
if (e.char == 'q'):
# for i in ["#0088dd", "#005e99", "#002841", "#2e2e2e"]:
# canvas.itemconfig(rect, fill=i)
# time.sleep(0.04)
for i in range(0, 3):
canvas.after(400, cycle_blue)
blue_step += 1
# ...
Any help?
Previous thoughts
According to #jasonharper:
The only thing that time.sleep() accomplishes in a Tkinter program is to
lock up the GUI completely. Delays and event-driven programming don't get
along very well - the proper approach is to use .after() to schedule the
next step of your animation a little bit into the future, and then return to
the mainloop.
I'll try this method and update in a few days. It may not work, but I'll mark this correct until then. Thank you, #jasonharper.
Edit: I cannot mark correct for two days.
I want Python to kind of ignore a statement that is unlikely to be called in a function that is often called.
I do not have a formal education in programming, so please excuse my lackluster ability to desribe things. I will try to explain the concept by example.
Say I am writing a video game, first-person shooter, drawing 60 frames per second.
In the settings menu, the user can select whether or not to display the name of other players above their head. If they disable this, I store this value as showplayernames = False.
Then in my drawing function that outputs the graphics I have:
def draw():
#code that draws the graphics on screen
if showplayernames:
#code that draws the name of players on screen
I call this function 60 times a second, but there is absolutely no point for checking if showplayernames is True 60 times a second. It will not change that often, in fact I could make this a kind of "constant" during play by preventing it to change. If showplayernames is False, then the third and fourth lines of the code are completely redundant, but they are executed nevertheless. The computer isn't smart enough to know it can ignore it, and there is a performance difference: reading a value and then checking if it is false takes time.
I could write two copies of the game (or at least the draw() function), one with only the first two lines when the user selects not to show names in the settings, and another without the if statement, and then run the appropriate one.
def draw_with_names():
#code that draws the graphics on screen
#code that draws the name of players on screen
def draw_without_names():
#code that draws the graphics on screen
Although looping through either of these 60 times a second is more efficient than running draw() ,this is obviously not the way to go. There are dozens of settings like this.
So how do software and game designers implement these kind of "software-wide" settings efficiently?
I'm not a game developer, but here's one option. Create a list of function pointers and add or remove from the list based on settings. Example:
def draw_player_names():
# Code to overlay names
def draw_fps():
# Code to overlay fps
def draw():
# Main code to draw a frame of the game
# Hold all the functions to call
optional_funcs = []
if showplayernames: optional_funcs.append(draw_player_names)
if show_fps: optional_funcs.append(draw_fps)
# Main game loop
while True:
draw()
for f in optional_funcs: f()
This can be extended for any number of functions/options.
not an game designer, but here is my voice.
You could store settings inside json file next to you python, but then you need to cover reading, getting right values etc.
You could use Environment variables to store value but that would end up using still "if" in the code.
Game designers use triggers and events to get things done, and on the lowest level I would assume those things also use if's.
system-wide-settings will in the end be used with if's
You could use overwrites based on event/trigger and use "same" draw function in both times but that only complicates code, and we all know to "keep it simple".
Sorry if this is not the answer you were looking for.
As Matthias said, you shouldn't really bother about this kind of optimization. Look at these two very silly functions:
def lot_of_ifs(settings):
#do something
a=2**10
b=2**10
c=2**10
for setting in settings:
if setting:
#do something more
a=2**10
b=2**10
c=2**10
def no_ifs():
#do something
a=2**10
b=2**10
c=2**10
timeit("lot_of_ifs([0,0,0,0,0])", globals=globals())
0.2630380000000514
timeit("no_ifs()", globals=globals())
0.10232830000040849
The cost of creating a list, looping over it, and executing five ifs is about 0.16 seconds for one million iterations, or 160 nanoseconds per iteration, while at 60 fps you have 16.6 million nanoseconds to execute your code.
I thought using Screen.tracer(0) disabled animation in Python Turtle Graphics. However in the following program, if you comment out screen.update(), there is still some animation happening - the turtle trail gets drawn although the turtle doesn't "move" (or get updated). What is happening here please? Is there way to make updating the screen completely manual?
import turtle
def move():
my_turtle.forward(1)
my_turtle.right(1)
screen.update() # Comment out this line to see issue.
screen.ontimer(move, 10)
screen = turtle.Screen()
my_turtle = turtle.Turtle()
my_turtle.shape("turtle")
screen.tracer(0)
move()
turtle.done()
No, screen.tracer(0) doesn't stop all animation. Some turtle commands like end_fill() invoke screen.update() directly, some like dot() invoke it due to other methods that they in turn invoke. You only advise the system when you call update(), not control it completely.
Put your update() calls where you believe you need them, and don't assume certain methods force an update, otherwise future updates of turtle might break your code. (I.e. someone might actually fix turtle.)
For potentially helpful details, see my tracer() rules of thumb and information about the first argument's numeric value
In turtle.py, forward() calls _go() which sets an endpoint, then calls _goto()
_goto() creates a newline if line segments get above 42
if len(self.currentLine) > 42: # 42! answer to the ultimate question
# of life, the universe and everything
self._newLine()
The value appears to be arbitrary; you could set it to something higher, but then there are pauses where nothing appears to be happening.
def _newLine(self, usePos=True):
"""Closes current line item and starts a new one.
Remark: if current line became too long, animation
performance (via _drawline) slowed down considerably.
"""
I have some code as follows:
# My code here
turtle.bye()
After that, is there any way I can reopen the turtle window.
I know you can do turtle.clearscreen() but that does not close the turtle window.
I will accept any answer which allows me to close the turtle graphics window and then reopen it without opening and running another python program to do this.
Thank you in advance
I've seen situations where the approach of #LukeTimmons worked but not always reliably and not in every situation. Give this solution a try:
import time
import turtle
turtle.dot(200, 'green')
time.sleep(2)
turtle.bye()
# These two lines (indirectly) resurrect turtle environment after turtle.bye()
turtle.Turtle._screen = None # force recreation of singleton Screen object
turtle.TurtleScreen._RUNNING = True # only set upon TurtleScreen() definition
turtle.dot(200, 'red')
turtle.mainloop()
It resets two flags that keep turtle from starting up again. It may be safer to create your own turtle after restart rather than use the default turtle which may point back to the departed environment.
There may be other ways but this is the only way I know.
from turtle import *
def turtle1():
#Your code here
turtle1()
turtle.bye()
turtle1()
This should re-run your code without re-typing it.
The following code creates a window in which a python turtle follows wherever your mouse goes. However, it draws indescriminately of whether the user is clicking to draw or not. My code is the following:
Note: You must have pythonwin installed in order for this program to work properly
import turtle, win32api
while True:
# turtle.penup()
user = win32api.GetCursorPos()
mousepos = [user[0]-510,-1*(user[1])+ 410]
turtle.goto(mousepos)
turtle.onclick(turtle.pendown())
In theory, this would only draw when the user is pressing and holding the mouse, but it doesn't work in practice. The commented code will simply cause it to not draw at all. Any advice?
turtle.onclick(turtle.pendown())
Here, you are calling pendown(), which returns probably None; then you're passing this None to onclick(). It probably means "do nothing on a click". That's probably not what you want.
According to #Gibby's comment, you want:
def clicked(*args): # args ignored
turtle.pendown()
turtle.onclick(clicked)