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)
...
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 just discovered the turtle module, and I'm trying to use it. I'd like to run a program that draws a static graphic, and then close the window when the space bar is pressed. This program draws the graphic just fine – but then nothing happens when I press the – and fairly soon the blue wheel is spinning, and the window has become unresponsive in the mind of Windows.
How to do better? How to wait while remaining a "responsive window"?
Python 3.9,
Windows 10
import turtle
from time import sleep
t = turtle.Turtle()
turtle.onkey(turtle.bye, ' ')
t.forward(150)
t.rt(108)
while True:
sleep(0.2)
You're missing a call to the listen() method so your key press won't be heard. Also, don't reinvent the event loop -- neither while True: nor sleep() belong in an event-driven world like turtle:
from turtle import Screen, Turtle
turtle = Turtle()
turtle.forward(150)
turtle.right(108)
screen = Screen()
screen.onkey(screen.bye, ' ')
screen.listen()
screen.mainloop()
So I am making a game with python turtle where the player moves the turtle left and right by pressing the corresponding arrow keys. The turtle cannot move up or down in any way. Only left and right. But when my turtle reaches a certain xcor value I want the turtle to stop moving even if I am still pressing that arrow key. But still be able to move the opposite direction with the other arrow key.
def playerRight():
player.goto(player.xcor() + 8,player.ycor())
if player.xcor() >= 200:
def playerLeft():
player.goto(player.xcor() - 8,player.ycor())
if player.xcor() <= -200:
screen.onkey(playerRight,'Right')
screen.onkey(playerLeft,'Left')
screen.listen()
But I have no clue what to put in my conditionals. A reply is greatly appreciated! Thanks!
Perhaps try changing your code to only move the turtle if it won't go too far, like so.
def playerRight():
if player.xcor() <= 192:
player.goto(player.xcor() + 8,player.ycor())
Now it only moves to the right if it doing so won't make it go to far. You then do the same thing for the playerLeft() function
You also have your inequalities the wrong way around (< where you need >)
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()