Thursday 7 May 2009

Animating a bounce

In this section we will look at the way that computer animation is produced. Our starting point is a program to show a ball bouncing around the walls of a closed container.

We will make the container 400 pixels wide and 450 pixels high:



When designing an animation program, it is necessary to separate the things which happen before the animation begins from the things which happen during the animation. The things occuring before the animation are put inside a section of program called the setup function, and are enclosed by curly brackets:


void setup(){
<Put anything here that you want to
happen once at the start of the program
>
}


Notice the word void which appears before the name setup. This means that we just want the function to carry out some tasks without returning any calculated result.

The first lines to add to the setup function will create the graphics window with the correct pixel size and set the background to white:



void setup(){
size (400,450);
background(255);
}


We now add the frameRate function:


frameRate(30);


The purpose of this is to specify how many times per second the screen will be updated during the animation. Each new screen image is termed a 'frame', by analogy with the frames of a movie film.

The final steps are to add the variables which specify the size of the bouncing ball, its speed, and its position on the screen. We will start with the ball in the middle of the bottom edge of the screen:


void setup(){
frameRate(30);
size (400,450);
background(255);
xPosition=width/2;
yPosition=height;
ballSize=8;
xspeed=6;
yspeed=6;
}


Now we are ready to do some animation. The things which happen each time the screen is refreshed are put inside a function called draw:


void draw(){
<Put anything here that you want to happen
once every time the frame is refreshed
>
}



We begin by drawing the ball as a circle, making use of the variables which specify its position and size.


void draw(){
ellipse(xPosition, yPosition, ballSize, ballSize);
}


We now change the values of xPosition and yPosition slightly, so the ball will appear to have moved when the next frame is drawn:


xPosition=xPosition+xspeed;
yPosition=yPosition-yspeed;


The amount by which the ball moves is determined by the speed variables. Remember that the coordinate system measures downwards from the top of the window, so we need to reduce the yPosition value if the ball moves upwards.

The program at the moment would work for a few frames, with the ball travelling diagonally upwards to the right from its starting position, but it would soon disappear off the edge of the screen. We need to find a way of making it bounce back...

Conditionals

The key to making the ball bounce is to detect when it reaches the edge of the container, then reverse its movement direction. This is done by a conditional statement with the keyword IF:


if (xPosition>width){
xspeed=-xspeed;
}


As soon as the horizontal position of the ball goes beyond the right-hand wall, the horizontal component of the speed will be reversed and the ball will start to move back into the container.

We can use a similar conditional statement to detect the ball escaping through the left-hand wall, and reverse its horizontal speed again to bounce it back:


if (xPosition<0){
xspeed=-xspeed;
}


Two more conditionals are needed to bounce the ball back from the bottom and top walls of the container:


if (yPosition>height){
yspeed=-yspeed;
}
if (yPosition<0){
yspeed=-yspeed;
}


Let's put everything together:


Bounce 1


int xPosition;
int yPosition;
int ballSize;
int xspeed,yspeed;

void setup(){
frameRate(30);
size (400,450);
background(255);
xPosition=width/2;
yPosition=height;
ballSize=8;
xspeed=6;
yspeed=6;
}

void draw(){
xPosition=xPosition+xspeed;
yPosition=yPosition-yspeed;
ellipse(xPosition, yPosition, ballSize, ballSize);
if (xPosition>width){
xspeed=-xspeed;
}
if (xPosition<0){
xspeed=-xspeed;
}
if (yPosition>height){
yspeed=-yspeed;
}
if (yPosition<0){
yspeed=-yspeed;
}
}


When the program is run, the ball begins from the bottom of the window and bounces as it encounters each of the walls. A trail is left behind to show its motion (figure 1).



It is easy to change the program to show the single bouncing ball without leaving a trail behind. We just add a background command as the first line of the draw( ) function:


void draw(){
background(255);
xPosition=xPosition+xspeed;
yPosition=yPosition-yspeed;
...............


This clears the screen at the start of each new animation frame, so only the current ball position is displayed (figure 2):



Now that we understand a basic animation sequence for a bouncing ball, let's be more adventurous. Suppose that we replace the empty container with one half-full of water. Imagine a scenario in which the ball travels faster through the air than through the water. Each time the ball enters the water in the bottom half of the container it slows down, and each time it escapes from the water again, it speeds up. How do we model the change in speed?

Fortunately, conditionals can help us with this problem again. This time, however, we need two options:


if (yPosition>height/2){
speedFactor=1;
}
else
{
speedFactor=4;
}


A variable called speedFactor has been used. When the ball is in the lower half of the window, so that the y position is more than half way down the window, we set the speed factor to 1. This represents a slow speed. When the ball is in the upper half of the window, the speed factor is set to a value four times faster.

Notice the use of the key word ELSE. The expression on the IF line is checked, and the command following it is carried out if the result is true. The command following ELSE is carried out instead when the result is false. The structure is:


if (this is true){
<do this>
}
else
{
<do this instead>
}


We can make our model sillier still. Suppose that instead of a bouncing ball we have a bouncing bubble, and that the bubble expands when it is in the air and contracts when it enters the water. We can change the size in a similar way to changing the speed by using a size factor:


if (yPosition>height/2){
speedFactor=1;
sizeFactor=1;
}
else
{
speedFactor=4;
sizeFactor=4;
}



Here is the completed program, which makes use of much of the same code as the earlier bouncing ball model:




Bounce 2


int xPosition;
int yPosition;
int ballSize,ball;
int xspeed,yspeed;
int speedFactor,sizeFactor;

void setup(){
frameRate(30);
size (400,450);
background(255);
xPosition=width/2;
yPosition=height;
ballSize=8;
xspeed=4;
yspeed=4;
}

void draw(){
background(255);
fill(0,0,255);
rect(0,height/2,width,height/2);
if (yPosition>height/2){
speedFactor=1;
sizeFactor=1;
}
else
{
speedFactor=4;
sizeFactor=4;
}
xPosition=xPosition+xspeed*speedFactor;
yPosition=yPosition-yspeed*speedFactor;
ball=ballSize*sizeFactor;
fill(255);
ellipse(xPosition, yPosition, ball, ball);
if (xPosition>width){
xspeed=-xspeed;
}
if (xPosition<0){
xspeed=-xspeed;
}
if (yPosition>height){
yspeed=-yspeed;
}
if (yPosition<0){
yspeed=-yspeed;
}
}



Run the program and you will see the bubble changing size and speed as it moves between the water and air layers (figure 3):