Python's Turtle 的时间和按键事件

Time and keypress events with Python's Turtle

我正在尝试用乌龟创建一个简单的游戏:

因此,我需要用键盘控制一些事件,并在一定时间后触发其他事件。如果没有一个循环,我想不出这样做的方法,在循环中我检查子弹和敌人之间的距离,但如果我这样做,我无法在循环期间控制主乌龟。

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()