1. From Bouncing Ball to Angry Birds

This notebook explores the idea that objects on our sketch appear to move in various ways:

  • Falls
  • Projectiles
  • Bounces

This is a magic trick... nothing really "moves"... it is just the canvas redrawn in an appropriate way that gives the illusion of movement.

1.1 A Ball

Like we did for Lab 2, let's draw an object at a specific location:

In [1]:
void setup() {
    size(200, 200);
}

void drawBall(float x, float y, float scale) {
    fill(255, 0, 0);
    ellipse(x, y, 10 * scale, 10 * scale);
}

void draw() {
    drawBall(100, 20, 1);
}
Sketch #1:

Sketch #1 state: Loading...

1.2 Global Variables

First, we'll create two global variables, and initialize them to the same values as above:

In [2]:
float x = 100;
float y = 20;

void setup() {
    size(200, 200);
}

void drawBall(float x, float y, float scale) {
    fill(255, 0, 0);
    ellipse(x, y, 10 * scale, 10 * scale);
}

void draw() {
    drawBall(x, y, 1);
}
Sketch #2:

Sketch #2 state: Loading...

Now, let's move the assignment to the setup() function:

In [4]:
float x;
float y;

void setup() {
    size(400, 100);
    x = width/2;
    y = 20;
}

void drawBall(float x, float y, float scale) {
    fill(255, 0, 0);
    ellipse(x, y, 10 * scale, 10 * scale);
}

void draw() {
    drawBall(x, y, 1);
}
Sketch #4:

Sketch #4 state: Loading...

Nothing too interesting there. I did use the special variables width and height that are automatically defined to be the size of the canvas. But other than that, it is just a picture of a red ball sitting quietly in space.

1.3 Brownian Motion

Let's try a slight variation. Do you know the idea of Brownian Motion (sometimes called particle theory). This is basically just the idea that small objects will randomly move because they are hit will atoms or molecules.

Warning: I did not say "Brownie in motion"... that is a small chocolate treat that is on the move.

We can simulate Brownian Motion by simply moving the ball a little left, right, or stay in the same place. We use the fact that random(2) - 1 represents either a -1, 0, or 1.

In [5]:
println(random(2) - 1);
Sketch #5:

Sketch #5 state: Loading...
-0.7309886215007491
0.901475877332913
In [7]:
// Global variables: 
// defined here, used in setup() and draw()

float x;
float y;

void setup() {
    size(200, 200);
    x = width/2;
    y = height/2;
}

void drawBall(float x, float y, float scale) {
    fill(255, 0, 0);
    stroke(255, 0, 0);
    ellipse(x, y, 10 * scale, 10 * scale);
}

void draw() {
    drawBall(x, y, 1);
    x = x + random(2) - 1;
    y = y + random(2) - 1;
}
Sketch #7:

Sketch #7 state: Loading...

It looks like the ball is moving randomly about, doesn't it. You can make the effect even stronger by clearing the background before you redraw the ball:

In [14]:
// Global variables: 
// defined here, used in setup() and draw()

float x;
float y;

void setup() {
    size(200, 200);
    x = width/2;
    y = height/2;
}

void drawBall(float x, float y, float scale) {
    fill(255, 0, 0);
    ellipse(x, y, 10 * scale, 10 * scale);
}

void draw() {
    background(168);
    drawBall(x, y, 1);
    x = x + random(3) - 1;
    //y = y + 0;
}
Sketch #14:

Sketch #14 state: Loading...

1.4 Velocity

Now, instead of having the ball randomly move each time step, let's have the ball move in a particular direct. To do this, we will create two new variables that will keep track of the velocity (speed) of the ball in the x and y directions.

On each time step, we will move the ball an appropriate amount.

In [17]:
// Give the ball velocities 
// in the x and y directions:

float vx;
float vy;

float x;
float y;

float dt;  
float t;

void setup() {
    size(200, 200);
    x = width/2;
    y = 50;
    dt = 0.1;  
    t = 0;
    vx = 1.0;
    vy = 0.0;
}

void drawBall(float x, float y, float scale) {
    fill(255, 0, 0);
    ellipse(x, y, 10 * scale, 10 * scale);
}

void draw() {
    background(128, 128, 128);
    float dx = vx * dt;    
    x = x + dx;
    
    float dy = vy * dt;
    y = y + dy;

    drawBall(x, y, 1);
    
    t = t + dt;
}
Sketch #17:

Sketch #17 state: Loading...

Somewhat interesting... but where did it go?

1.4.1 Bouncing off the walls

To keep the ball "on the canvas", we need to see when it is beyond bounds, and turn the ball around. All we need to do is switch the velocity to go in the opposite direction. So if the ball is going to the right and hits a wall, we make it go to the left.

To allow the ball to do one thing if it hits a wall, and something else if it doesn't we need to introduce the idea of flow of control.

We can control the flow of a program using if/else, like this:

if (EXPRESSION) {
    STATEMENT;
    ...
} else {
    STATEMENT;
    ...
}
In [20]:
float vx;
float vy;

float x;
float y;

float dt;  
float t;

void setup() {
    size(200, 200);
    x = width/2;
    y = 50;
    dt = 0.1;  
    t = 0;
    vx = 10.0;
    vy = 7.5;
}

void drawBall(float x, float y, float scale) {
    fill(255, 0, 0);
    ellipse(x, y, 50 * scale, 50 * scale);
}

void draw() {
    background(0, 255, 0);
    float dx = vx * dt;    
    if (((x + dx) > width) || ((x + dx) < 0)) {
        vx = vx * -1;
    } else {
        x = x + dx;
    }
    
    float dy = vy * dt;
    if (((y + dy) > height) || ((y + dy) < 0)) {
        vy = vy * -1;
    } else {
        y = y + dy;
    }

    drawBall(x, y, 1);
    
    t = t + dt;
}
Sketch #20:

Sketch #20 state: Loading...

1.4.2 Gravity

Now, the final step: let's add gravity. At each timestep, we'll add a gravity component to vy. Over time, that will get bigger and bigger.

In [22]:
float g = 9.8; 

float vx;
float vy;

float x;
float y;

float dt;  
float t;

void setup() {
    size(200, 500);
    x = width/2;
    y = 50;
    dt = 0.1;  
    t = 0;
    vx = 5.0;
    vy = 0.0;
}

void drawBall(float x, float y, float scale) {
    fill(255, 0, 0);
    ellipse(x, y, 10 * scale, 10 * scale);
}

void draw() {
    //background(0, 0, 128);
    // gravity
    vy = vy + g * dt;
    
    float dx = vx * dt;    
    if (((x + dx) > width) || ((x + dx) < 0)) {
        vx = vx * -1;
    } else {
        x = x + dx;
    }
    
    float dy = vy * dt;
    if (((y + dy) > height) || ((y + dy) < 0)) {
        vy = vy * -1;
    } else {
        y = y + dy;
    }

    drawBall(x, y, 1);
    
    t = t + dt;
}
Sketch #22:

Sketch #22 state: Loading...

1.4.3 Dampening

That is weird... it keeps bouncing! We probably want to lose a little bit of energy each time it "hits something." We merely don't give the full amount when we change directions.

In [25]:
float g = 9.8; 

float vx;
float vy;

float x;
float y;

float dt;  
float t;

void setup() {
    size(200, 500);
    x = width/2;
    y = 50;
    dt = 0.1;  
    t = 0;
    vx = 50.0;
    vy = 0.0;
}

void drawBall(float x, float y, float scale) {
    fill(255, 0, 0);
    ellipse(x, y, 10 * scale, 10 * scale);
}

void draw() {
    // gravity
    background(255);
    vy = vy + g * dt;
    
    float dx = vx * dt;    
    if (((x + dx) > width) || ((x + dx) < 0)) {
        vx = vx * -0.6;
    } else {
        x = x + dx;
    }
    
    float dy = vy * dt;
    if (((y + dy) > height) || ((y + dy) < 0)) {
        vy = vy * -0.6;
    } else {
        y = y + dy;
    }

    drawBall(x, y, 1);
    
    t = t + dt;
}
Sketch #25:

Sketch #25 state: Loading...

1.5 Interactivity

Nice! Now let's drop the ball with the mouse:

In [26]:
float g = 9.8; 

float vx;
float vy;

float x;
float y;

float dt;  
float t;

void setup() {
    size(200, 500);
    x = width/2;
    y = 50;
    dt = 0.1;  
    t = 0;
    vx = 50.0;
    vy = 0.0;
}

void drawBall(float x, float y, float scale) {
    fill(255, 0, 0);
    ellipse(x, y, 10 * scale, 10 * scale);
}

void draw() {
    // gravity
    background(168);
    vy = vy + g * dt;
    
    float dx = vx * dt;    
    if (((x + dx) > width) || ((x + dx) < 0)) {
        vx = vx * -0.8;
    } else {
        x = x + dx;
    }
    
    float dy = vy * dt;
    if (((y + dy) > height) || ((y + dy) < 0)) {
        vy = vy * -0.8;
    } else {
        y = y + dy;
    }

    drawBall(x, y, 1);
    
    t = t + dt;
}

void mousePressed() {
    x = mouseX;
    y = mouseY;
    vx = 0.0;
    vy = 0.0;
}
Sketch #26:

Sketch #26 state: Loading...

1.6 Angry Birds

Ok, but it just drops. What if we could click, drag, and release, and the distance we dragged was proportional to a vector in the opposite direction of where we want to send it. Angry Birds!

Click below and drag:

In [31]:
float g = 9.8; 

float vx;
float vy;

float x;
float y;

float dt;  
float t;

void setup() {
    size(500, 500);
    x = width/2;
    y = 50;
    dt = 0.2;  
    t = 0;
    vx = 0.0;
    vy = 0.0;
    background(255);
}

void drawBall(float x, float y, float scale) {
    fill(255, 0, 0);
    ellipse(x, y, 10 * scale, 10 * scale);
}

boolean mouseIsDown = true;

void draw() {
    if (mouseIsDown) return;
    background(255);
    
    // gravity
    vy = vy + g * dt;
    
    float dx = vx * dt;    
    if (((x + dx) > width) || ((x + dx) < 0)) {
        vx = vx * -0.8;
    } else {
        x = x + dx;
    }
    
    float dy = vy * dt;
    if (((y + dy) > height) || ((y + dy) < 0)) {
        vy = vy * -0.8;
        if (abs(vy) > 30) {
            //drawBall(x, y, 2);
            fill(255, 0,0);
            ellipse(x, y, vy, 5);
            noLoop();
            return;
         }
    } else {
        y = y + dy;
    }

    drawBall(x, y, 1);
    
    t = t + dt;
}

void mousePressed() {
    mouseIsDown = true;
    x = mouseX;
    y = mouseY;
    background(255);
    drawBall(x, y, 1);
    vx = 0.0;
    vy = 0.0;
}

void mouseReleased() {
    vx = (x - mouseX);
    vy = (y - mouseY);
    mouseIsDown = false;
    loop();
}

void mouseDragged() {
    background(255);
    drawBall(x, y, 1);
    line(x, y, mouseX, mouseY);
}
Sketch #31:

Sketch #31 state: Loading...

To make a really "angry birds" like game, we'll need to detect more than collisions with the walls, floor, and ceiling. We'll do that later, once we learn how to make real objects.

1.7 Conclusion

In this notebook we have seen that motion is just imagined. We saw Brownian Motion, velocity, gravity, and a ball with an applied force (ala Angry Birds).

New ideas and jargon:

  • global variable
  • perceived motion
  • gravity
  • bounce
  • flow of control
  • if/else
  • interactivity
  • statement versus expression