Python's Turtle 的时间和按键事件
Time and keypress events with Python's Turtle
我正在尝试用乌龟创建一个简单的游戏:
- 用户控制的乌龟可以在按下
space
时发射子弹
- 在随机位置创建敌方海龟
- 如果敌人被子弹击中,则敌人被消灭并移动到新的位置。
- 如果子弹离开屏幕,它就会消失。
- 当子弹移动时,玩家应该仍然可以移动。
- 如果敌人在 20 秒内没有被消灭,玩家就输了。
因此,我需要用键盘控制一些事件,并在一定时间后触发其他事件。如果没有一个循环,我想不出这样做的方法,在循环中我检查子弹和敌人之间的距离,但如果我这样做,我无法在循环期间控制主乌龟。
import turtle as trtl
from random import randint
import time
class Game():
def __init__(self):
self.scr = trtl.Screen()
self.scr.update()
self.player = trtl.Turtle()
self.player.shape('turtle')
self.player.penup()
trtl.onkeypress(self.forward,'w')
trtl.onkeypress(self.backwards,'s')
trtl.onkeypress(self.left,'a')
trtl.onkeypress(self.right,'d')
trtl.onkeypress(self.shoot,'space')
trtl.listen()
self.enemy = trtl.Turtle()
self.enemy.shape('square')
self.enemy.penup()
self.enemy.speed(0)
self.move_enemy()
self.bullet = trtl.Turtle()
self.bullet.penup()
self.bullet.hideturtle()
self.bulletShot = False
def forward(self):
self.player.forward(5)
def backwards(self):
self.player.back(5)
def left(self):
self.player.left(6)
def right(self):
self.player.right(6)
def shoot(self):
if self.bulletShot == False:
self.bullet.speed(0)
self.bullet.goto(self.player.pos())
self.bullet.seth(self.player.heading())
self.bullet.showturtle()
self.bulletShot = True
def move_enemy(self):
x = randint(-300,300)
y = randint(-300,300)
self.enemy.hideturtle()
self.enemy.goto(x,y)
self.enemy.showturtle()
def play(self):
startTime = time.time()
print(time.time() - startTime)
while time.time() - startTime < 20:
if self.bulletShot:
self.bullet.forward(1)
collision = self.bullet.distance(self.enemy.pos()) < 10
isIn = (self.bullet.pos()[0] <= 300 and
self.bullet.pos()[0] >= -300 and
self.bullet.pos()[1] <= 300 and
self.bullet.pos()[1] >= -300)
if not(isIn):
self.bullet.hideturtle()
self.bulletShot = False
elif collision:
self.bullet.hideturtle()
self.bulletShot = False
self.move_enemy()
startTime = time.time()
self.player.write('You loose')
self.scr.exitonclick()
game = Game()
game.play()
我尝试了一个更简单的版本,一只乌龟自动循环移动,另一只乌龟用键盘控制,效果很好。
import turtle as trtl
def up():
jane.sety(jane.pos()[1] + 10)
def down():
jane.sety(jane.pos()[1] - 10)
scr = trtl.Screen()
scr.update()
bob = trtl.Turtle()
bob.penup()
bob.seth(180)
bob.setx(300)
bob.speed(1)
jane = trtl.Turtle()
jane.penup()
trtl.onkeypress(up,'w')
trtl.onkeypress(down,'s')
trtl.listen()
while True:
if bob.pos()[0] > -300:
bob.forward(10)
else:
break
scr.exitonclick()
有没有办法用 turtle 解决这个问题?
让我们重新设计游戏以使用乌龟的事件系统,通过使用计时器事件来控制动作,同时仍然使用您的计时器来限制游戏时间:
from turtle import Screen, Turtle
from random import randint
import time
class Game():
def __init__(self):
self.startTime = -1
self.screen = Screen()
self.screen.tracer(False)
self.player = Turtle()
self.player.shape('turtle')
self.player.penup()
self.enemy = Turtle()
self.enemy.shape('square')
self.enemy.penup()
self.move_enemy()
self.bullet = Turtle()
self.bullet.hideturtle()
self.bullet.penup()
self.bulletShot = False
self.screen.onkeypress(self.forward, 'w')
self.screen.onkeypress(self.backwards, 's')
self.screen.onkeypress(self.left, 'a')
self.screen.onkeypress(self.right, 'd')
self.screen.onkeypress(self.shoot, 'space')
self.screen.listen()
def forward(self):
self.player.forward(5)
self.screen.update()
def backwards(self):
self.player.back(5)
self.screen.update()
def left(self):
self.player.left(6)
self.screen.update()
def right(self):
self.player.right(6)
self.screen.update()
def shoot(self):
if not self.bulletShot:
self.bullet.setposition(self.player.position())
self.bullet.setheading(self.player.heading())
self.bullet.showturtle()
self.bulletShot = True
self.screen.update()
def move_enemy(self):
x = randint(-300, 300)
y = randint(-300, 300)
self.enemy.goto(x, y)
self.screen.update()
def play(self):
if self.startTime == -1:
self.startTime = time.time()
if self.bulletShot:
self.bullet.forward(1)
x, y = self.bullet.position()
if not(-300 <= x <= 300 and -300 <= y <= 300):
self.bullet.hideturtle()
self.bulletShot = False
elif self.bullet.distance(self.enemy.pos()) < 10:
self.bullet.hideturtle()
self.bulletShot = False
self.move_enemy()
self.startTime = time.time()
self.screen.update()
if time.time() - self.startTime > 20:
self.player.write('You loose!')
self.screen.update()
else:
self.screen.ontimer(self.play, 10)
screen = Screen()
game = Game()
game.play()
screen.mainloop()
仍然有点粗糙,但应该可以玩。您在原始代码中有一个 self.scr.update()
调用,但没有初始调用 tracer()
,它什么也不做。在这里,我们使用 tracer()
和 update()
通过手动控制所有屏幕更新来加速和平滑运动。
我设法解决了这个问题,而没有更改太多代码,也没有使函数 play()
递归。问题是,如果 while
里面的 if
需要一个 else
,否则,不会记录按键。所以我给了它一些事情要做,现在它可以按我的意愿工作了。
while time.time() - startTime < 20:
if self.bulletShot:
self.bullet.forward(3)
...
else:
self.scr.update()
我正在尝试用乌龟创建一个简单的游戏:
- 用户控制的乌龟可以在按下
space
时发射子弹 - 在随机位置创建敌方海龟
- 如果敌人被子弹击中,则敌人被消灭并移动到新的位置。
- 如果子弹离开屏幕,它就会消失。
- 当子弹移动时,玩家应该仍然可以移动。
- 如果敌人在 20 秒内没有被消灭,玩家就输了。
因此,我需要用键盘控制一些事件,并在一定时间后触发其他事件。如果没有一个循环,我想不出这样做的方法,在循环中我检查子弹和敌人之间的距离,但如果我这样做,我无法在循环期间控制主乌龟。
import turtle as trtl
from random import randint
import time
class Game():
def __init__(self):
self.scr = trtl.Screen()
self.scr.update()
self.player = trtl.Turtle()
self.player.shape('turtle')
self.player.penup()
trtl.onkeypress(self.forward,'w')
trtl.onkeypress(self.backwards,'s')
trtl.onkeypress(self.left,'a')
trtl.onkeypress(self.right,'d')
trtl.onkeypress(self.shoot,'space')
trtl.listen()
self.enemy = trtl.Turtle()
self.enemy.shape('square')
self.enemy.penup()
self.enemy.speed(0)
self.move_enemy()
self.bullet = trtl.Turtle()
self.bullet.penup()
self.bullet.hideturtle()
self.bulletShot = False
def forward(self):
self.player.forward(5)
def backwards(self):
self.player.back(5)
def left(self):
self.player.left(6)
def right(self):
self.player.right(6)
def shoot(self):
if self.bulletShot == False:
self.bullet.speed(0)
self.bullet.goto(self.player.pos())
self.bullet.seth(self.player.heading())
self.bullet.showturtle()
self.bulletShot = True
def move_enemy(self):
x = randint(-300,300)
y = randint(-300,300)
self.enemy.hideturtle()
self.enemy.goto(x,y)
self.enemy.showturtle()
def play(self):
startTime = time.time()
print(time.time() - startTime)
while time.time() - startTime < 20:
if self.bulletShot:
self.bullet.forward(1)
collision = self.bullet.distance(self.enemy.pos()) < 10
isIn = (self.bullet.pos()[0] <= 300 and
self.bullet.pos()[0] >= -300 and
self.bullet.pos()[1] <= 300 and
self.bullet.pos()[1] >= -300)
if not(isIn):
self.bullet.hideturtle()
self.bulletShot = False
elif collision:
self.bullet.hideturtle()
self.bulletShot = False
self.move_enemy()
startTime = time.time()
self.player.write('You loose')
self.scr.exitonclick()
game = Game()
game.play()
我尝试了一个更简单的版本,一只乌龟自动循环移动,另一只乌龟用键盘控制,效果很好。
import turtle as trtl
def up():
jane.sety(jane.pos()[1] + 10)
def down():
jane.sety(jane.pos()[1] - 10)
scr = trtl.Screen()
scr.update()
bob = trtl.Turtle()
bob.penup()
bob.seth(180)
bob.setx(300)
bob.speed(1)
jane = trtl.Turtle()
jane.penup()
trtl.onkeypress(up,'w')
trtl.onkeypress(down,'s')
trtl.listen()
while True:
if bob.pos()[0] > -300:
bob.forward(10)
else:
break
scr.exitonclick()
有没有办法用 turtle 解决这个问题?
让我们重新设计游戏以使用乌龟的事件系统,通过使用计时器事件来控制动作,同时仍然使用您的计时器来限制游戏时间:
from turtle import Screen, Turtle
from random import randint
import time
class Game():
def __init__(self):
self.startTime = -1
self.screen = Screen()
self.screen.tracer(False)
self.player = Turtle()
self.player.shape('turtle')
self.player.penup()
self.enemy = Turtle()
self.enemy.shape('square')
self.enemy.penup()
self.move_enemy()
self.bullet = Turtle()
self.bullet.hideturtle()
self.bullet.penup()
self.bulletShot = False
self.screen.onkeypress(self.forward, 'w')
self.screen.onkeypress(self.backwards, 's')
self.screen.onkeypress(self.left, 'a')
self.screen.onkeypress(self.right, 'd')
self.screen.onkeypress(self.shoot, 'space')
self.screen.listen()
def forward(self):
self.player.forward(5)
self.screen.update()
def backwards(self):
self.player.back(5)
self.screen.update()
def left(self):
self.player.left(6)
self.screen.update()
def right(self):
self.player.right(6)
self.screen.update()
def shoot(self):
if not self.bulletShot:
self.bullet.setposition(self.player.position())
self.bullet.setheading(self.player.heading())
self.bullet.showturtle()
self.bulletShot = True
self.screen.update()
def move_enemy(self):
x = randint(-300, 300)
y = randint(-300, 300)
self.enemy.goto(x, y)
self.screen.update()
def play(self):
if self.startTime == -1:
self.startTime = time.time()
if self.bulletShot:
self.bullet.forward(1)
x, y = self.bullet.position()
if not(-300 <= x <= 300 and -300 <= y <= 300):
self.bullet.hideturtle()
self.bulletShot = False
elif self.bullet.distance(self.enemy.pos()) < 10:
self.bullet.hideturtle()
self.bulletShot = False
self.move_enemy()
self.startTime = time.time()
self.screen.update()
if time.time() - self.startTime > 20:
self.player.write('You loose!')
self.screen.update()
else:
self.screen.ontimer(self.play, 10)
screen = Screen()
game = Game()
game.play()
screen.mainloop()
仍然有点粗糙,但应该可以玩。您在原始代码中有一个 self.scr.update()
调用,但没有初始调用 tracer()
,它什么也不做。在这里,我们使用 tracer()
和 update()
通过手动控制所有屏幕更新来加速和平滑运动。
我设法解决了这个问题,而没有更改太多代码,也没有使函数 play()
递归。问题是,如果 while
里面的 if
需要一个 else
,否则,不会记录按键。所以我给了它一些事情要做,现在它可以按我的意愿工作了。
while time.time() - startTime < 20:
if self.bulletShot:
self.bullet.forward(3)
...
else:
self.scr.update()