Search code examples
pythonturtle-graphicspython-3.2

Moving turtle according to the arrow keys


I am trying to make my turtle move according to the arrow keys on my keyboard. Does anybody know how to make a turtle in python 3.2.2 move according to the command of my arrow keys? By the way, my turtle is in the form of a tank if that affects anything. Here is my code:

import turtle

unVar1 = 25
unVar2 = 100
unVar3 = 90
unVar4 = 150
unVar5 = -30
unVar6 = 75
unVar7 = 50
def polySquare(t, x, y, length):
    t.goto(x, y)
    t.setheading(270)

    t.begin_poly()

    for count in range(4):
        t.forward(length)
        t.left(90)

    t.end_poly()

    return t.get_poly()

def polyRectangle(t, x, y, length1, length2):
    t.goto(x, y)
    t.setheading(270)

    t.begin_poly()

    for count in range(2):
        t.forward(length1)
        t.left(90)
        t.forward(length2)
        t.left(90)

    t.end_poly()

    return t.get_poly()

def tankCursor():

    """
    Create the tank cursor.  An alternate solution is to toss the temporary turtle
    and use the commented out polygon assignments instead of the poly function calls
    """

    temporary = turtle.Turtle()

    screen = turtle.getscreen()

    delay = screen.delay()

    screen.delay(0)

    temporary.hideturtle()
    temporary.penup()

    tank = turtle.Shape("compound")

    # tire1 = ((10, unVar1), (10, unVar1 - unVar6), (10 + 30, unVar1 - unVar6), (10 + 30, unVar1))
    tire1 = polyRectangle(temporary, 10, unVar1, unVar6, 30)  # Tire #1
    tank.addcomponent(tire1, "gray", "black")

    # tire2 = ((110, unVar1), (110, unVar1 - unVar6), (110 + 30, unVar1 - unVar6), (110 + 30, unVar1))
    tire2 = polyRectangle(temporary, 110, unVar1, unVar6, 30)  # Tire #2
    tank.addcomponent(tire2, "gray", "black")

    # tire3 = ((110, unVar2), (110, unVar2 - unVar6), (110 + 30, unVar2 - unVar6), (110 + 30, unVar2))
    tire3 = polyRectangle(temporary, 110, unVar2, unVar6, 30)  # Tire #3
    tank.addcomponent(tire3, "gray", "black")

    # tire4 = ((10, unVar2), (10, unVar2 - unVar6), (10 + 30, unVar2 - unVar6), (10 + 30, unVar2))
    tire4 = polyRectangle(temporary, 10, unVar2, unVar6, 30)  # Tire #4
    tank.addcomponent(tire4, "gray", "black")

    # bodyTank = ((20, unVar3), (20, unVar3 - 130), (20 + 110, unVar3 - 130), (20 + 110, unVar3))
    bodyTank = polyRectangle(temporary, 20, unVar3, 130, 110)
    tank.addcomponent(bodyTank, "black", "gray")

    # gunTank = ((65, unVar4), (65, unVar4 - 100), (65 + 20, unVar4 - 100), (65 + 20, unVar4))
    gunTank = polyRectangle(temporary, 65, unVar4, 100, 20)   # Gun
    tank.addcomponent(gunTank, "black", "gray")

    # exhaustTank = ((50, unVar5), (50, unVar5 - 20), (50 + 10, unVar5 - 20), (50 + 10, unVar5))
    exhaustTank = polyRectangle(temporary, 50, unVar5, 20, 10)
    tank.addcomponent(exhaustTank, "black", "gray")

    # turretTank = ((50, unVar7), (50, unVar7 - 50), (50 + 50, unVar7 - 50), (50 + 50, unVar7))
    turretTank = polySquare(temporary, 50, unVar7, 50)  # Turret
    tank.addcomponent(turretTank, "red", "gray")

    turtle.addshape("tank", shape=tank)

    del temporary

    screen.delay(delay)

tankCursor()  # creates and registers the "tank" cursor shape

turtle.shape("tank")

turtle.up()  # get rid of the ink

# show our tank in motion
while True:
    turtle.forward(100)
    turtle.left(90)
    turtle.forward(100)
    turtle.left(180)
    turtle.forward(200)

Solution

  • You can use turtle's built in key event handlers. This is the link to the documents: https://docs.python.org/3.2/library/turtle.html

    Using your code, everything stays the same up to tankCursor() (line 98). Now going down in order, this is what I did.

    tankCursor()  # creates and registers the "tank" cursor shape
    
    tank = turtle
    tank.shape("tank")
    
    turtle.up()  # get rid of the ink
    
    screen = turtle.Screen()
    

    I made the tank variable so you are interacting with that (you did turtle.foward, turtle.backward, etc.) instead of turtle. Just good practice, and now you can have multiple tanks on the screen, or multiple characters if you wish. The turtle.up() is from your original code. The screen = turtle.Screen() is so your code gets notified of the key events, ie. when the user clicks a key / releases a key.

    def moveright():
        tank.forward(40)
    
    def moveleft():
        tank.backward(40) 
    

    These are just functions, to move the tank right and left. Notice I used tank.forward, not turtle.forward. This corresponds to the tank = turtle variable above. The name 'tank' can be anything you want, just make sure you use that name all the way through your code. The .forward and .backward functions are the same type you used in

    while True:
        turtle.forward(100)
        turtle.left(90)
        turtle.forward(100)
        turtle.left(180)
        turtle.forward(200)
    

    all of those should work in the moveright / moveleft functions as well.

    screen.onkeypress(moveright, "Right")
    screen.onkeypress(moveleft, "Left")
    
    screen.listen()
    screen.mainloop()
    

    Now is the magic. The 2 screen.onkeypress lines tell the computer to listen for a pressed key. It takes 2 arguments, the first is a function (that is what the moveright, moveleft parts are) and the second argument is a string relating to the desired key on the keyboard. Eg. 'e' -> 'e' key, 'w' -> letter w, -> 'Up' -> up arrow -> 'Right' -> right arrow, so on, so forth. **The key names must be in quotes, like in the example above. if you do screen.onkeypress(moveright, Right) it will throw an error.

    The screen.listen() tells the computer to start listing for the key events, and the screen.mainloop starts Turtle's mainloop so it continues to look until turtle.done() is called. The screen.mainloop is very important because without it your program would end and no events would be received.

    Here is the full code, feel free to copy / paste and use it however you wish. Again, code continues from tankCursor(), line 98.

    tankCursor()  # creates and registers the "tank" cursor shape
    
    tank = turtle
    tank.shape("tank")
    
    turtle.up()  # get rid of the ink
    
    screen = turtle.Screen()
    
    def moveright():
        tank.forward(40)
    
    def moveleft():
        tank.backward(40)
    
    screen.onkeypress(moveright, "Right")
    screen.onkeypress(moveleft, "Left")
    
    screen.listen()
    screen.mainloop()