tutorials

Animation with Turtle Graphics

Posted on by Abraham

In the previous post — Programming with Understanding — I explained why Turtle Graphics are great for learning about how the world works, through programming. In this post we’ll program our own basic animation by using Python’s turtle module.

Animation

All animation (indeed, all moving pictures) is fundamentally nothing more than consecutive pictures being shown so quickly that it simulates continuous motion. Each picture is called a frame. Each frame must differ from the previous one slightly, and quickly showing the frames one after the other gives the illusion of continuous motion, hence the word ‘animate’ as in ‘bring to life’. The frames have to be shown at a rate of about 12 or more frames per second (fps) for a person to experience them as an animation. Modern film generally uses 24 frames per second.

12 Frames from Eadweard Muybridge’s series The Horse in Motion.

The Horse in Motion animated.

Animating with Python turtle

Let’s now create our own basic animation by using Python’s turtle module: a square that moves across the screen, starting on the left, and moving to the right.

An animated square

Now, think about how animation works as a series of images that differ slightly. To create the illusion of a single square moving to the right, we’ll need to draw a lot of squares, each one positioned a little to the right of the previous one, and show these quickly. So what our code would need to do is to clear the previous square, then draw a new square and move to the right, before starting again.

The first thing we’ll need to do, is to draw a square. Let’s put the code that draws a square into its own function so that it’s easier to read the code. We’ll also make sure that the screen is a specific size, so that it’s possible to move the turtle exactly off-screen. We’ll move the turtle off-screen, on the left. Then we’ll implement our animation algorithm above where we repeatedly clear the previous square, draw a new square, and move forward a bit (as a new turtle starts off facing to the right of the screen).

import turtle

screen = turtle.Screen()    # create a new screen
screen.setup(500,500)       # 500 x 500 window

don = turtle.Turtle()       # create a new [ninja] turtle
don.speed(0)                # make it move faster

def draw_square() :         # a function that draws one square
    for side in range(4) :
        don.forward(100)
        don.left(90)

don.penup()                 # go off-screen on the left
don.goto(-350, 0)
don.pendown()

while True :                # now do this repeatedly, to animate :
    don.clear()             # - clear all the turtle's previous drawings
    draw_square()           # - draw a square
    don.forward(10)         # - move forward a bit

An animated square moving from left to right, but with jerky movement.

Controlling frames

We can see that it does indeed look like a single square that’s moving across the screen, but that the animation also looks a bit broken. It’s as a result of our individual frames — in the code above, the screen decides when to update the picture, and that’s often in the middle of a square being drawn, so our frames are just a lot of part-squares as can be seen in the frame below:

One frame but which shows an uncompleted square.

We need to control that a frame is shown only after a square has been completed. This can be done by first telling the screen to not show anything automatically, with screen.tracer(0), and then telling it to show (as one frame in our animation) only after a square has been completed, with screen.update().

Controlling speed

One other thing that we now need to do, is to move forward by a much smaller distance each time. The reason is that, when the screen was choosing when to show frames, it was using many frames to show the drawing of each square, perhaps 10, so that the forward movement only actually happened after every 10th frame. If the frame rate of our animation was also 10 fps, that would mean forward movement happened only once each second. Whereas when we’re choosing to display a frame manually only after a square has completed, 10 frames now means 10 squares instead of just 1, and forward movement then takes place 10 times per second instead of once. So, as a lot more forward movement is taking place for the same amount of frames, the square looks like it moves forward a lot faster. We therefore have to reduce the distance moved between each frame to get the square to animate forward again at a slower, reasonable speed.

The complete animation

Finally, let’s hide the turtle itself, so that we only see the square drawings, and make the pen line a bit thicker.

import turtle

screen = turtle.Screen()
screen.setup(500,500)
screen.tracer(0)            # tell screen to not show automatically

don = turtle.Turtle()
don.speed(0)
don.width(3)
don.hideturtle()            # hide donatello, we only want to see the drawing

def draw_square() :
    for side in range(4) :
        don.forward(100)
        don.left(90)

don.penup()
don.goto(-350, 0)
don.pendown()

while True :
    don.clear()
    draw_square()
    screen.update()         # only now show the screen, as one of the frames
    don.forward(0.02)

An animated square moving from left to right with fluid movement.

Animating with sprites

There is an even easier way, but we didn’t start off with it as it’s better to come to understand fundamentals whenever you have the chance. The easier way is if we don’t draw the picture ourselves with turtle, but simply use an image as the turtle’s shape. That can be done with a combination of the screen’s addshape("yourImage.gif") function and the turtle’s shape("yourImage.gif") function. It must be a .gif image, other file types aren’t allowed. You can use an animated .gif, but turtle will only use the first frame and ignore the rest, so it’s better to use a non-animated .gif image. The string that you pass in to the two functions is the location of the .gif image relative to the folder where the program itself is saved (meaning only the filename if they lie in the same folder, as below):

import turtle

screen = turtle.Screen()
screen.setup(500,500)
screen.tracer(0)
screen.addshape("fireball.gif")   # register the image with the screen as a shape

don = turtle.Turtle()
don.speed(0)
don.shape("fireball.gif")         # now set the turtle's shape to it

don.penup()
don.goto(-350, 0)

while True :
    screen.update()
    don.forward(0.01)

An animated fireball moving from left to right.

Simulating interaction

In this post, we’ve created an animated square that simply moves to the right, by drawing many squares, each one a little to the right of the previous one. What if we wanted to simulate that an object interacts with another object, like a ball bouncing on a floor? That would happen in the same way, with a ball moving closer to the floor in each frame, then changing direction and moving further away from the floor again once it has collided, just like a real ball would. In other words, you can think of the frames of an animation as photos that have been taken many times a second — which is exactly what a video camera actually does.

All the frames of an animated ball superimposed, with notes by animator Preston Blair.

Games

That’s it for animation. We’ve now laid the groundwork for games as well, as games are also simulations that simply use animation for all the moving graphics. In the next post — Games with Turtle Graphics — we’ll get into the details, then progress to creating our own games.