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.
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.
So right now, i have a platformer and i want to make it so when i click on a button, the whole game restarts.
In main.py:
level=Level(level_map,screen)
while running:
if game_state=='game_active':
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
pygame.font.quit()
sys.exit()
level.run()
screen.blit(sky_surface,(0,0))
pygame.display.update()
clock.tick(60)
in level.py:
class Level:
def __init__(self,level_data,surface):
self.display_surface=surface
self.level_building(level_data)
def level_building(self,tilesheet):
self.coins=pygame.sprite.Group()
self.player=pygame.sprite.GroupSingle()
for row_index,row in enumerate(level_map):
for col_index,cell in enumerate(row):
self.x=col_index*tile_size
self.y=row_index*tile_size
if cell=='R':
self.coin_sprite=Recyclables((self.x+22,self.y+55))
self.coins.add(self.coin_sprite)
if cell=='P':
self.player_sprite=Player((self.x+10,self.y))
self.player.add(self.player_sprite)
def collisions(self):
playercoin=pygame.sprite.groupcollide(self.coins,self.player,True,False) # kills the coin (to show it has been picked up)
if len(playercoin)==1:
self.score+=1
def run(self):
self.coins.draw(self.display_surface)
self.collisions()
self.player.draw(self.display_surface)
After my game finishes running, what is a good way to restart everything, and respawn all the sprites that were killed? (did not show the kill code since it'd be too long) so far i've tried killing all sprites after the game but i don't know how to re-draw everything.
In PyGame, you're in full control of what's being drawn on the screen every frame, so I'm not sure why you wouldn't be sure how to redraw things.
Since you apparently have already encapsulated your game logic into the Level class, restarting the level shouldn't require more than just
level = Level(level_map, screen)
so subsequent calls to level.run() use a fresh level.
(Also, unless you're doing esoteric things that you're not showing us here, you shouldn't necessarily need to even "kill sprites".)
I've been testing the turtle library for about 3 days now. One recurring 'issue' that I've been getting is the traceback error whenever I exit my application window. The terminal displays rows of details regarding the turtle update function and it ends with:
_tkinter.TclError: can't invoke "update" command: application has been destroyed
Here's my code:
import turtle
wn = turtle.Screen()
wn.title("Game Window")
wn.bgcolor("black")
wn.setup(width=1000, height=650)
wn.tracer(0)
run = True
while run:
wn.update()
I've been trying to wrap my head around the traceback report. I'm assuming it happens because the application continuously updates the window (as you can see in the while run block). So, there is a possibility that, once I exit the window, the application is already processing the wn.update() function, and it returns an error because it did not finish its operation. If that is the case, then what should I do about the update function? If not then, please, explain to me the issue and solution. Thank you!
The problem is your loop:
while run:
wn.update()
This is the wrong way to approach Python turtle programming. I see this loop often in SO questions so there must be a book ("Programming Python Turtle by Bad Example") or tutorial somewhere teaching people the wrong way to approach turtle.
Generally, I'd suggest you avoid tracer() and update() until your program is basically working and you now need to optimize its performance. If you do use tracer(), then you should only call update() when you are finished making changes and you want the user to see the current display. Something like:
from turtle import Screen, Turtle
screen = Screen()
screen.setup(width=1000, height=650)
screen.title("Game Window")
screen.tracer(0)
turtle = Turtle()
radius = 1
while radius < 300:
turtle.circle(radius, extent=1)
radius += 0.25
screen.update() # force above to be seen
screen.mainloop()
A key point to note is that our program ends with a mainloop() call which passes control onto Tk(inter)'s event loop. That's the same event loop that receives the window close event and closes down turtle cleanly.
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()
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)
...