Animation with Turtle Graphics
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.
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
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:
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)
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)
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.
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.