I've just started working on a version of Snake using Turtle, and I've encountered an issue. I want the snake to move indefinitely, but also to allow the user to move the snake with the keyboard. I got the snake to move from user input, but I can't figure out how to get the snake to keep moving in the same direction while there is no input, whilst preventing it from ignoring user input:
while True:
win.onkey(up,"Up")
win.onkey(right,"Right")
win.onkey(down,"Down")
win.onkey(left,"Left")
win.listen()
#moves the snake one unit in the same direction it is currently facing
movesnake()
I'm new to Turtle, and this is my guess at how to solve this issue - which obviously doesn't work. Any help would be appreciated. I'm conscious Pygame might make this easier but since I've already started with Turtle, I would prefer to get a Turtle solution, if possible.
An event-driven environment like turtle should never have while True: as it potentially blocks out events (e.g. keyboard). Use an ontimer() event instead.
Generally, onkey() and listen() don't belong in a loop -- for most programs they only need to be called once.
Here's a skeletal example of an autonomous turtle being redirected by user input:
from turtle import Screen, Turtle
def right():
snake.setheading(0)
def up():
snake.setheading(90)
def left():
snake.setheading(180)
def down():
snake.setheading(270)
def movesnake():
snake.forward(1)
screen.ontimer(movesnake, 100)
snake = Turtle("turtle")
screen = Screen()
screen.onkey(right, "Right")
screen.onkey(up, "Up")
screen.onkey(left, "Left")
screen.onkey(down, "Down")
screen.listen()
movesnake()
screen.mainloop()
Related
I am trying to create a turtle crossing game but every time I run the program neither the screen.listen() gets executed nor the screen.exitonclick()
After running the program on clicking on the turtle window it does not close neither the turtle moves forward
import turtle
from turtle import Screen
from player import Player
import time
screen = Screen()
screen.setup(width=600, height=600)
screen.tracer(0)
player = Player()
screen.listen()
screen.onkey(player.go_up(), "Up")
turtle.TurtleScreen._RUNNING = True
game_is_on = True
while game_is_on:
time.sleep(0.1)
screen.update()
screen.exitonclick()
Although I tried adding the ._RUNNING method, yet it does not make any difference
There are a few issues here:
while game_is_on: is an infinite loop since game_is_on is never changed from True to False. Anything after the loop will never run. Avoid using this pattern; the typical way to make a real-time rendering loop in turtle is ontimer.
turtle.TurtleScreen._RUNNING = True messes with an undocumented internal property. Unless you have an absolute need to, you shouldn't touch internal properties in libraries because you may be corrupting the instance's state and the property can disappear after an update. I'm not sure what you're trying to do here, but either figure out a way using the public API or drop this code entirely if it's not really needed (I don't think it is--I've never used it in a turtle program).
Although the code for Player wasn't posted, screen.onkey(player.go_up(), "Up") is likely incorrect. It invokes the go_up() method immediately and sets its return value, probably None, as the onkey handler. You probably meant screen.onkey(player.go_up, "Up") which doesn't call the method immediately, but instead passes it to the handler so it can be called later on by the turtle library, when the key is pressed.
With a little stub for Player, I'd suggest a setup like:
import turtle
class Player:
def __init__(self):
self.turtle = turtle.Turtle()
def go_up(self):
self.turtle.setheading(90)
self.turtle.forward(10)
def tick():
#### the main loop; move/update entities here ####
screen.update()
screen.ontimer(tick, 1000 // 30)
screen = turtle.Screen()
screen.setup(width=600, height=600)
screen.tracer(0)
player = Player()
screen.onkey(player.go_up, "Up")
screen.listen()
tick()
screen.exitonclick()
Now, you don't have any code in tick yet. This is the main update/rendering loop. The player's movement will be jerky because it's directly wired to the keyboard's retrigger mechanism. If this behavior isn't what you want, I suggest reacting to key presses and changing the player's position only inside of tick. See How to bind several key presses together in turtle graphics? for an example of this.
I've written the following #Game Loop trying to teach my students a lesson. The turtle would not move or respond to any of the functions until I added the line WIN.update(). Why would that be necessary? Other turtle #Game Loops I've created have not needed it. When does it become a requirement to help the turtle respond to both key commands and user created functions?
enter image description here
In a turtle program, the update() is only necessary if you've previously done tracer(0), and doesn't directly affect keyboard events.
However, your program isn't assembled properly as while True:, or equivalent, defeats an event-driven environment like turtle. The addition of update() gave your program a chance to clear the event queue. What we really should use is a timed event. This is what I would have expected your program fragment to look like:
def game_loop():
if RUNNING:
Move() # Move the Turtle
Barriers() # Barrier Check
WIN.update() # Only if Win.tracer(0) is in effect
WIN.ontimer(game_loop, 100) # Delay in milliseconds
WIN.onkey(Up, 'Up')
WIN.onky(Down, 'Down')
WIN.onkey(Left, 'Left')
WIN.onkey(Right, 'Right')
WIN.listen()
game_loop()
WIN.mainloop()
Note that onkey() and listen() do not belong in the game loop, they only need to be applied once.
I'm creating a game using the turtle module. I included in my code something like this to smooth out the animation:
screen.tracer(0)
Then I update the screen with:
screen.update()
However, when I run the code, the animation freezes. Does anyone know what's happened here?
well it works correctly!
the screen should always be in freeze mode (because of .tracer(0) method), unless it sees the .update() and then because of this method it refresh it state and then back to the freeze mode.
source: tracer documentation
so basically it should update the screen once but if you want to update the screen constantly, you should put the screen.update() (and your entire code) in a while loop. here is an example:
from turtle import Screen
screen = Screen()
screen.tracer(0)
game_is_on = True
while game_is_on:
screen.update()
# your code
screen.exitonclick()
I am trying to get the turtle to stop moving forward when I press the escape key. When I press escape, nothing happens! Can anyone tell me why? A solution would be greatly appreciated.
import turtle
screen = turtle.Screen()
running = True
def stop():
running = False
print(running)
while running:
turtle.forward(1)
screen.onkey(stop, "Esc")
screen.listen()
I see several problems with your code. The primary one is a missing global statement in stop(). Secondary ones include: mixing the turtle function and object APIs; using key name 'Esc' instead of 'Escape'; putting onkey() and listen() in a loop; and potentially blocking events with your while loop.
I believe this code should do what you want:
from turtle import Screen, Turtle
running = True
def stop():
global running
running = False
def run():
if running:
turtle.forward(1)
screen.ontimer(run)
screen = Screen()
screen.onkey(stop, 'Escape')
screen.listen()
turtle = Turtle()
run()
screen.mainloop()
I'm working on Python game using turtles.
I have a player object that moves up and down (jump) on key press. I'm trying to add a moving platform that the player has to jump on.
I tried putting the moving platform in a while loop. The problem is since the while loop is running to keep the platform moving, the program does not detect key press.
I tried moving turtle.listen() inside the main while loop but that didn't work.
How do I keep the platform moving, in a while True loop, and have the listener active?
# moving platform
while True:
s13.backward(3)
if s13.xcor() > 250:
s13.setheading(0)
if s13.xcor() < -200:
s13.setheading(180)
...
turtle.listen()
turtle.onkey(jump, "Up")
Any advice is appreciated...
A while True: statement has no place in an event driven environment like turtle. There are at least a couple of solutions available to you. The most straight forward is to use turtle's built-in ontimer() events to have a function independently run at a fixed (or variable) interval.
Another option is to introduce threading to the program. However, since turtle is tkinter-based, you have to channel all the graphics operations through the main thread, which complicates things.
Try searching StackOverflow for:
python turtle ontimer
python turtle threading
A crude example:
from turtle import Turtle, Screen
screen = Screen()
s13 = Turtle('square')
s13.color('red', 'blue')
s13.shapesize(1, 3, 2)
s13.penup()
def jump():
s13.color(*reversed(s13.color()))
# moving platform
def move_platform():
s13.backward(3)
if s13.xcor() > 250:
s13.setheading(0)
if s13.xcor() < -200:
s13.setheading(180)
screen.ontimer(move_platform, 100)
# ...
screen.onkey(jump, "Up")
screen.listen()
move_platform()
screen.mainloop()
The platform floats back and forth. If you hit the up arrow (after clicking on the window to make it active) you'll see the platform swap its fill and outline colors as it floats.
You need to move:
turtle.listen()
turtle.onkey(jump, "Up")
to the top. Like this:
turtle.listen()
turtle.onkey(jump, "Up")
while True:
s13.backward(3)
if s13.xcor() > 250:
s13.setheading(0)
if s13.xcor() < -200:
s13.setheading(180)
...