dark mode light mode Search Menu
Search

Remote Controlled Turtles

Vicki Burton on Flickr

What do all games have in common? Control, of course! It’s the player who decides where to explore, who to battle, and when to run away. These choices require an input mechanism. Whether you’re using a video game controller, a touch screen, or a keyboard, the game’s software needs to detect user inputs and respond to them appropriately. In software, we call this event handling.

Though user-generated events are fundamental to all games, the code associated with them can be a bit tricky. But fear not! We’re here to demystify the process, using a short Python program with a Turtle sprite that responds to key presses.

To start, navigate to www.repl.it and select ‘Python with Turtle’ from the ‘Select your Language’ box.

Setup

Add the following code to the left-hand editor:

from turtle import Turtle, Screen

playground = Screen()
thomas = Turtle()
thomas.shape('turtle')
thomas.penup()

This code creates all the basic pieces we need to build our program. We import our libraries, define our key objects, and adjust our sprite so that Thomas looks like a turtle.

Functions

Every function ends with two angled brackets: ( and ). For example: sort() or penup().

A function is essentially a series of predefined mini-actions rolled into one big action. Take making a pizza. First, the chef rolls out the dough, then he slathers on some sauce, drowns the entire thing in cheese, and throws it in the oven. When ordering a pizza, you assume the chef knows all of these steps. You don’t list them out when placing your order; it would take too long, and you might make a mistake!

The same idea applies to functions. When you call a function, you assume that it’ll accomplish its task as efficiently as possible — whether it’s sorting a list or drawing some pictures onscreen — but you don’t probe into the details.

Sometimes, the user has an element of choice in a function call. For example, you can pick the size of your pizza and decide what kind of condiments it should have. In programming terms, this means passing variables (condiments, size) to the function (chef) who manipulates this information in predefined ways to create the output you expect (a large pepperoni pizza).

These special variables are known as parameters, and they’re located between the opening and closing brackets of a function. Not all functions have parameters, and when they do, they have to be given in a specific format and in a specific order. When the chef asks for the size of your pizza, you can’t answer “onion”. You have to choose between small, medium, and large.

Some functions are accessed from libraries, like the “shape” and “penup” functions from the previous section. Other functions we define ourselves. In this program, we’re going to create a “travel” function that describes how Thomas moves around the playground.

Add the following code to the left-hand editor:

# Make Thomas move around the screen
def travel():
    thomas.forward(1)
    playground.ontimer(travel, 10)

The “def” keyword tells that program that you’re “defining” a function. In this case, our function is called “travel” and has no parameters. Every line included in the function must start with a tab and is executed every time the function is called.

The first line uses the Turtle library’s “forward” function to make Thomas move forward one pixel. The second line is a bit tricky, because it involves our first event.

Timer Events

User-generated events include button presses, key presses, mouse clicks, or even voice commands and motion detection. Some events can happen without user input, the best example being timers.

An event handler is a function designed to respond to a specific event. The event handler for pressing the spacebar might make a character jump, while the event handler for the ‘return’ key brings the user back to the game’s main menu. To work properly, each event handler must be registered to a listener.

You can picture a listener as a loop running separately from the main program. Listeners wait around for user-generated events, and if detected, call the associated event handler.

The exact terminology varies a bit from language to language, but the principle stays the same: programs can’t just magically detect user input. Some piece of code, somewhere, has to be constantly “listening” for things like key presses and mouse clicks.

Now, looking back at the code for our first event:

playground.ontimer(travel, 10)

The “playground” is our listener object. The “ontimer” function registers the event handler (the travel function, passed as the first parameter) to be executed whenever T milliseconds have elapsed. The value of T is specified with the second parameter: in this case, 10.

This naturally creates a nice little loop. We start our program by calling the travel function. Thomas moves. The “ontimer” event is set with a countdown of 10 seconds. When time’s up, the event handler — travel() — is triggered and starts the loop all over again. Result: Thomas continues to move forward in a single direction. Unless a key is pressed, of course.

Key Press Events

Add the following code to your editor:

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

Here, we define four separate event handlers and register them with “onkey” function. The second parameter indicates which key triggers the event handler. In this example we specify the four arrow keys, but we could easily have used ‘w’, ‘a’, ‘d’, and ’s’. As for the event handlers themselves, you may have noticed that they look a little odd:

lambda: thomas.setheading(90)
lambda: thomas.setheading(180)
lambda: thomas.setheading(0)
lambda: thomas.setheading(270)

The code in the second half of these lines spins Thomas around to face a new direction: up (90 degrees), left (180 degrees), etc.

The “lambda” keyword is a shortcut for creating a new function. So the code:

lambda: thomas.setheading(90)

Does the exact same thing as the code:

def turn_direction_top():
	thomas.setheading(90)

In practical terms, “lambda” is used to make functions that are only one line and aren’t ever going to be used again. This allows programs to save space and can make code easier to read.

Remember how functions expect their parameters in a certain format? (You can’t order an “onion” sized pizza.) As its first parameter, the “onkey” function expects the name of a function with no parameters. Since “thomas.setheading(90)” is a function with one parameter, it’s disqualified. To get around this annoying limitation we wrap the “setheading” function in a lambda.

Our temporary lambda function has no parameters, making it an acceptable candidate, and once executed the lambda passes control over to the “setheading” function. It’s a bit like a game of telephone tag! The user presses a key, the listener detects it and triggers the event handler (the lambda), and the lambda calls the function to change Thomas directions.

Finishing Up

We’re missing two little lines of code to get our remote control turtle up and running! Add these at the bottom of your program:

playground.listen()
travel()

The “listen” function makes the playground start detecting events. The first call to the “travel” function gets Thomas moving, and from there, the main loop takes over and the program runs smoothly.

Complete Code Listing

from turtle import Turtle, Screen

playground = Screen()
thomas = Turtle()
thomas.shape('turtle')
thomas.penup()

# Make Thomas move around the screen
def travel():
    thomas.forward(1)
    playground.ontimer(travel, 10)
    
# Define Thomas’s direction on each keypress
playground.onkey(lambda: thomas.setheading(90), 'Up')
playground.onkey(lambda: thomas.setheading(180), 'Left')
playground.onkey(lambda: thomas.setheading(0), 'Right')
playground.onkey(lambda: thomas.setheading(270), 'Down')
playground.listen()

travel()

Event handling may be a tricky beast, but it opens up the door to so many cool games! What program can you imagine with timers, key presses, and mouse events?

Learn More

INTRO TO PYTHON TURTLE

https://hourofpython.trinket.io/a-visual-introduction-to-python#/welcome/an-hour-of-code
http://interactivepython.org/runestone/static/IntroPythonTurtles/Summary/summary.html

FUNCTIONS AND PROCEDURES

https://kidscodecs.com/functions-and-procedures/

ABOUT EVENT LISTENERS

https://www.computerhope.com/jargon/e/event-listener.htm

TURTLE GRAPHICS DOCUMENTATION FOR PYTHON 2.7.5

https://docs.python.org/2/library/turtle.html

VIDEO TUTORIAL ABOUT EVENT DRIVEN PROGRAMMING

https://www.youtube.com/watch?v=k_7WUPN0krU