【问题标题】:How to move turtles in Python 3 with arrow keys如何在 Python 3 中使用箭头键移动海龟
【发布时间】:2017-04-17 10:28:14
【问题描述】:

我无法让我的乌龟跟随箭头键,如果能提供任何帮助,我们将不胜感激。我敢肯定这个问题以前有人问过,但我似乎找不到它,而且我找到的都是旧版本的。

import turtle
#screen
wn=turtle.Screen()
wn.bgcolor("lightblue")

I plan on this being a spaceship game
#Turtle Player
spaceship= turtle.Turtle()
spaceship.color("red")
spaceship.penup()
speed=1

这是我卡住的地方,我不知道如何让乌龟跟随 方向键

#keyboard bindings

while True:
    spaceship.forward(speed)

【问题讨论】:

  • 看看这个:dreamincode.net/forums/topic/… 用户atraub 的回答解释了如何做到这一点。
  • 称我为白痴,虽然我似乎无法在我的程序中实现这一点

标签: python turtle-graphics


【解决方案1】:

避免在海龟图形程序中使用像while True: 这样的无限循环,它可以防止某些事件触发。

下面是我能想出的让你的飞船可导航的最少代码。您应该能够在此基础上进行构建:

from turtle import Turtle, Screen

wn = Screen()
wn.bgcolor('lightblue')

spaceship = Turtle()
spaceship.color('red')
spaceship.penup()

speed = 1

def travel():
    spaceship.forward(speed)
    wn.ontimer(travel, 10)

wn.onkey(lambda: spaceship.setheading(90), 'Up')
wn.onkey(lambda: spaceship.setheading(180), 'Left')
wn.onkey(lambda: spaceship.setheading(0), 'Right')
wn.onkey(lambda: spaceship.setheading(270), 'Down')

wn.listen()

travel()

wn.mainloop()

在发出键盘命令之前单击海龟图形窗口以确保它正在侦听。此外,按键的工作方式还有其他方法,我在这里使用了 absolute 动作,但您可能希望 relative 每次按下都会逐渐修改您的方向。

【讨论】:

    【解决方案2】:

    首先,我们要了解基础知识。 为了让用户能够通过按键与乌龟进行交互,我们需要让窗口listen进行按键操作。由于您的屏幕名为wn,因此只需调用wn.listen()即可。

    现在海龟图形正在监听按键,你将如何告诉程序通过按键做某事?功能!假设您希望每次按下某个键时都创建一个新海龟;你需要像这样定义一个函数(你可以使用lambda作为函数,但现在,让我们坚持使用def

    def create_new_turtle():
        new_turtle = turtle.Turtle()
    

    请记住,在定义函数时,不应将任何positional arguments 传递到括号中,因为在使用函数时将无法传递参数,从而导致TypeError

    现在,让我们来看看我们如何在运行时在按键被按下时实际调用这些函数。启动wn.listen() 后,您现在只需要wn.onkeywn.onkeypress。使用上面的函数,如果你想在用户每次按下 SPACE 键时创建一个新的海龟:

    wn.onkey(create_new_turtle, 'space')
    

    你明白为什么我们不能将位置参数传递给函数吗?可以看到,在使用wn.onkey里面的函数时,我们没有调用它(因为我们没有在函数的右边加上括号)wn.onkey 为我们做这件事。

    利用我们学到的知识,让我们看看它们的实际应用:

    import turtle
    
    #Screen
    wn = turtle.Screen()
    wn.bgcolor("lightblue")
    
    #Turtle Player
    spaceship = turtle.Turtle()
    spaceship.color("red")
    spaceship.penup()
    
    #Constant
    speed = 1
    
    def up():
        spaceship.setheading(90)
    
    def down():
        spaceship.setheading(270)
        
    def left():
        spaceship.setheading(180)
    
    def right():
        spaceship.setheading(0)
    
    wn.listen()
    wn.onkey(up, 'Up')
    wn.onkey(down, 'Down')
    wn.onkey(left, 'Left')
    wn.onkey(right, 'Right')
    
    while True:
        spaceship.forward(speed)
    

    你能猜出这是做什么的吗?这很明显;当用户点击'Up'箭头时,将调用上面定义的up函数,当用户点击'Down'箭头时,将调用上面定义的down函数,以此类推。

    为单个命令定义整个函数似乎不对,我们不能这样做

    wn.onkey(spaceship.setheading(90), 'Up')
    wn.onkey(spaceship.setheading(270), 'Down')
    wn.onkey(spaceship.setheading(180), 'Left')
    wn.onkey(spaceship.setheading(0), 'Right')
    

    就像最受好评的答案一样,解决方案是使用lambda,可以将上面导致错误的代码更正为

    wn.onkey(lambda: spaceship.setheading(90), 'Up')
    wn.onkey(lambda: spaceship.setheading(270), 'Down')
    wn.onkey(lambda: spaceship.setheading(180), 'Left')
    wn.onkey(lambda: spaceship.setheading(0), 'Right')
    

    最后,如果你想让你的海龟在每次转弯时最大转动90 度,你可以在函数中使用if 语句来避免180 度转弯(随着函数变得越来越高级,最好使用def来定义函数而不是使用lambda):

    import turtle
    
    #Screen
    wn = turtle.Screen()
    wn.bgcolor("lightblue")
    
    #Turtle Player
    spaceship = turtle.Turtle()
    spaceship.color("red")
    spaceship.penup()
    
    #Constant
    speed = 1
    
    def up():
        if spaceship.heading() != 270:
            spaceship.setheading(90)
    
    def down():
        if spaceship.heading() != 90:
            spaceship.setheading(270)
        
    def left():
        if spaceship.heading() != 0:
            spaceship.setheading(180)
    
    def right():
        if spaceship.heading() != 180:
            spaceship.setheading(0)
    
    wn.listen()
    wn.onkey(up, 'Up')
    wn.onkey(down, 'Down')
    wn.onkey(left, 'Left')
    wn.onkey(right, 'Right')
    
    while True:
        spaceship.forward(speed)
    

    试运行:

    【讨论】:

      【解决方案3】:

      我有你的解决方案。该代码并不理想,但它可以工作,您可以使用它。你必须知道,乌龟的位置是默认的,你必须调整它。这就是为什么我指出我的乌龟要查找的设置方法。

      现在,您必须记住,right(deg)left(deg) 方法的意思是“请在给定的方向上以这样的角度转身”。

      所以请记住,您最后的方向是什么。

      理解这里的关键是你无权访问任何absolute。您只能更改与您当前位置相关的某些内容。所以,你不能左转,但如果你知道之前的方向,你就知道你应该把你的乌龟转多少度才能真正左转。

      我的任务代码是:

      import turtle
      wn = turtle.Screen()
      
      last_pressed = 'up'
      
      def setup(col, x, y, w, s, shape):
        turtle.up()
        turtle.goto(x,y)
        turtle.width(w)
        turtle.turtlesize(s)
        turtle.color(col)
        turtle.shape(shape)
        turtle.lt(90)
        turtle.down()
        wn.onkey(up, "Up")
        wn.onkey(left, "Left")
        wn.onkey(right, "Right")
        wn.onkey(back, "Down")
        wn.onkey(quitTurtles, "Escape")
        wn.listen()
        wn.mainloop()
      
      
      
      
      #Event handlers
      def up():
        global last_pressed
        if last_pressed == 'left':
          turtle.rt(90)
          turtle.fd(10)
        elif last_pressed == 'right':
          turtle.lt(90)
          turtle.fd(10)
        elif last_pressed == 'up':
          turtle.fd(10)
        else:
          turtle.rt(180)
          turtle.fd(10)
      
        last_pressed = 'up'
      
      def left():
        global last_pressed
        if last_pressed == 'left':
          turtle.fd(10)
        elif last_pressed == 'right':
          turtle.lt(180)
          turtle.fd(10)
        elif last_pressed == 'up':
          turtle.lt(90)
          turtle.fd(10)
        else:
          turtle.rt(90)
          turtle.fd(10)
      
        last_pressed = 'left'
      
      
      def right():
        global last_pressed
        if last_pressed == 'left':
          turtle.rt(180)
          turtle.fd(10)
        elif last_pressed == 'right':
          turtle.fd(10)
        elif last_pressed == 'up':
          turtle.rt(90)
          turtle.fd(10)
        else:
          turtle.lt(90)
          turtle.fd(10)
      
        last_pressed = 'right'
      
      def back():
        global last_pressed
        if last_pressed == 'left':
          turtle.lt(90)
          turtle.fd(10)
        elif last_pressed == 'right':
          turtle.rt(90)
          turtle.fd(10)
        elif last_pressed == 'up':
          turtle.rt(180)
          turtle.fd(10)
        else:
          turtle.fd(10)
      
        last_pressed = 'down'
      
      def quitTurtles():
        wn.bye()
      
      setup("blue",-200,200,2,2,"turtle")
      

      请记住,乌龟实际转动需要一些时间,所以不要按键,点击它们。

      我认为你可以走得更远。

      【讨论】:

      • 这应该可行,但由于实施(last_pressed + 硬编码转向),我投了反对票。有很多更好的方法可以做到这一点。 setheading 就像另一个答案所暗示的那样,或者在当前标题和所需标题之间获得差异并转动正确的数量可能会更干净。这个例子严重违反了不要重复自己的想法。