I am creating a snake game with food teleporting around map. I use ontimer with recursion at the end of function to emulate mole staying at a certain position for a time. I also make the mole to move if turtle ate it. But then, mole teleportation is called two time because of the already set function by ontimer.
def mole_teleport(is_loop=True):
rand_x = random.randint(-250, 250)
rand_y = random.randint(-250, 250)
mole.teleport(rand_x, rand_y)
if is_loop == False:
return
else:
screen.ontimer(mole_teleport, 3000)
tim = Player() #user_turtle
mole = Turtle("circle")
mole_teleport()
screen = Screen()
screen.setup(600, 600)
screen.listen()
screen.onkey(tim.turn_left, "Left")
screen.onkey(tim.turn_right, "Right")
game_is_on = True
while game_is_on:
tim.move()
if mole.distance(tim) < 20:
mole_teleport(is_loop=False)
my-ideal-diagram I tried to block recursion with argument. What I expect is teleportation timer to be refreshed from start after the turtle has eaten the mole and call mole_teleportation()
EDIT: Player() Class
from turtle import Turtle
SPEED = 3
class Player(Turtle):
def __init__(self) -> None:
super().__init__()
self.speed("fastest")
self.shape("turtle")
self.penup()
def move(self):
self.forward(SPEED)
def turn_left(self):
self.left(90)
def turn_right(self):
self.right(90)
turtle
is created with tkitner
which has similar function task_id = root.after(millisecond, function)
and it gives taks_id
which you can use to delete task, and later you could create new task
- so you would have only one timer-loop.
There are even method to access root
in turtle
but I would do it without ontimer
but using time.time()
in while
-loop to check if mole_time_to_teleport <= time.time()
and to teleport mole, and set new time mole_time_to_teleport += 3
.
And when snake ate mole then it can simply set mole_time_to_teleport = time.time()
to teleport mole at once - and function will also set mole_time_to_teleport += 3
.
I tried to recreate Player
but it slow, so I also use click on mole to eat it.
from turtle import *
import random
import time
class Player(Turtle):
def __init__(self):
super().__init__()
self.penup()
def move_forward(self):
self.forward(10)
def move_backward(self):
self.backward(10)
def turn_left(self):
self.left(10)
def turn_right(self):
self.right(10)
def mole_teleport():
global mole_time_to_teleport
if mole_time_to_teleport <= time.time():
rand_x = random.randint(-250, 250)
rand_y = random.randint(-250, 250)
mole.goto(rand_x, rand_y)
mole_time_to_teleport += 3 # set next teleport after 3 seconds
def eat_mole(x=None, y=None):
global mole_time_to_teleport
print('eat')
mole_time_to_teleport = time.time() # reset to current time
#mole_teleport() # while-loop will run `mole_teleport()` so I don't need it here
tim = Player()
mole = Turtle("circle")
mole.penup()
mole_time_to_teleport = time.time() # it will teleport at once, and it will set start position
screen = Screen()
screen.setup(600, 600)
screen.listen()
screen.onkey(tim.turn_left, "Left")
screen.onkey(tim.turn_right, "Right")
screen.onkey(tim.move_forward, "Up")
screen.onkey(tim.move_backward, "Down")
mole.onclick(eat_mole) # click on mole to eat it
game_is_on = True
while game_is_on:
mole_teleport() # run in every loop
if mole.distance(tim) < 20:
eat_mole()
time.sleep(.04) # slow down code - to use less CPU: 1s/.04 = 25 (Frames Per Second)
screen.update() # check events and execute `onclick`
EDIT:
The same but with class Mole
and list of moles
from turtle import *
import random
import time
# --- classes ---
class Player(Turtle):
def __init__(self, screen):
super().__init__()
self.penup()
screen.onkey(self.turn_left, "Left")
screen.onkey(self.turn_right, "Right")
screen.onkey(self.move_forward, "Up")
screen.onkey(self.move_backward, "Down")
def move_forward(self):
self.forward(10)
def move_backward(self):
self.backward(10)
def turn_left(self):
self.left(10)
def turn_right(self):
self.right(10)
class Mole(Turtle):
def __init__(self, shape, color="black"):
super().__init__(shape)
self.penup()
self.color(color)
self.time_to_teleport = time.time()
self.onclick(self.eat)
def check_teleport(self):
if self.time_to_teleport <= time.time():
rand_x = random.randint(-250, 250)
rand_y = random.randint(-250, 250)
#self.speed(0)
self.goto(rand_x, rand_y)
#self.speed(6)
self.time_to_teleport += 3 # set next teleport after 3 seconds
def eat(self, x=None, y=None):
print('eat')
self.time_to_teleport = time.time()
# --- functions ---
# --- main ---
screen = Screen()
screen.setup(600, 600)
tim = Player(screen)
moles = [
Mole("circle", "red"),
Mole("square", "green"),
Mole("triangle", "blue"),
]
screen.listen()
game_is_on = True
while game_is_on:
for mole in moles:
mole.check_teleport() # run in every loop
for mole in moles:
if mole.distance(tim) < 20:
mole.eat()
time.sleep(.04) # slow down code - to use less CPU: 1s/.04 = 25 (Frames Per Second)
screen.update() # check events and execute `onclick`