Animation
To be moved by that which does not move
An animation is a series of still pictures shown so quickly that they look like movement. Each picture is called a frame. Our programs can make animations by drawing a frame, showing it, and then repeating the process with a small change.
The Animation Loop
Every animation has the same three steps, repeated over and over.
- Clear the previous frame.
- Draw the new frame.
- Tick to show it and wait for the next one.
A square slides from the left side to the right. Here is what happens on each pass through the loop.
CLEAR_SCREEN()wipes the hidden drawing so it is empty again.DRAW_RECTdraws the square at the currentx.x ← x + 1moves the square one pixel to the right for the next frame.CLOCK_TICK(60)shows the picture and then waits until it is time for the next one.
The variable x is created before the loop. As we learned in the scope chapter, a
variable created inside a block disappears when the block ends. If x were created inside
the loop, it would be reset every frame, and nothing would move.
Why clear screen? Try deleting the CLEAR_SCREEN() line from the example above.
The square leaves a smear behind it.
The hidden drawing is not erased on its own. Everything we draw stays there until we
clear it. Without CLEAR_SCREEN, each new square is drawn on top of all the old ones.
Clearing also removes any background we drew. This means a background has to be drawn again every frame, right after clearing.
Frames per Second
The number given to CLOCK_TICK is the number of frames per second, often shortened to
FPS. CLOCK_TICK(60) shows 60 frames every second. Each frame lasts about 17
milliseconds.
CLOCK_TICK is smart about waiting. If drawing a frame took 5 milliseconds, it only
waits for the rest of the frame. That keeps the speed steady, even when some frames have
more to draw than others.
Our square moves one pixel per frame, so at 60 FPS it moves 60 pixels per second. To cross the canvas takes a little under 7 seconds.
This leads to an important point. Speed is measured per frame, not per second. If we
change CLOCK_TICK(60) to CLOCK_TICK(30), the square still moves one pixel per frame,
but there are half as many frames, so it moves half as fast. Try it.
Fewer frames per second also makes motion look choppier. Most games use 60.
The FPS has to be bigger than zero. A program can also never run faster than its code
allows. If a frame has too much to draw, CLOCK_TICK cannot make up the lost time.
Velocity
Instead of adding a fixed number, it is common to keep the speed in its own variable. We call it velocity. This lets us change how an object moves without changing the rest of the code.
Change speed to 6 and the square moves twice as far in the same time. A negative
velocity moves in the opposite direction. Since CSP has no negative sign in front of a
variable, we write 0 - speed to flip it.
Bouncing
With a velocity variable and an IF, we can make an object bounce off the walls.
The square is 40 pixels wide, so its right edge touches the wall when x is 360. When
it gets there, we put it exactly on the wall and flip the sign of speed. Positive
speed becomes negative, and the square turns around.
This animation uses
REPEAT UNTIL false, so it never ends on its own. Typically a loop in CSP stops after 100,000 iterations. At 60 frames per second, that is about 28 minutes before the program stops with an error. This is not the case whenCLOCK_TICK(n)is called though. Each timeCLOCK_TICK(n)is called, the iteration limit is increased by one, allowingREPEAT UNTIL falseto run forever.
Gravity
Real objects speed up as they fall. We can copy this by changing the velocity itself every frame. Here is a ball dropping and bouncing on the floor.
Each frame, gravity changes the velocity, and the velocity changes the position. That
chain is the key idea behind motion in games. The ball is 20 pixels in radius, so its
bottom touches the floor at y = 380. When it lands, we flip its velocity and multiply it
by 0.9, so each bounce is a bit smaller.
Counting Frames
Sometimes we want something to happen on a schedule. We can keep a counter that goes up
by one every frame, and use MOD to make a repeating pattern.
frame MOD 60 counts from 0 to 59 and starts again, so it repeats once per second at
60 FPS. The circle is drawn for the first half of every second, which makes it blink.
Practice
- Make a square that moves from top to bottom instead of left to right.
- Make the bouncing square also move up and down, so it bounces around the whole canvas. You will need a second velocity variable.
- Make a circle that grows by one pixel of radius each frame, and then shrinks again.
Next: Drawing Many Things