Jupyter at Bryn Mawr College

Public notebooks: /services/public/dblank / CS110 Intro to Computing / 2015-Fall / Lectures

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.

Stationary Object¶

We will use our drawObject code from last week. First, let's create a sketch where an object is drawn in position (x,y), where x and y are global variables. This allows setup() to initialize them, and draw() to use them.

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

float x;
float y;

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

void drawBall(float x, float y, int w, int h) {
fill(255, 0, 0);
ellipse(x, y, w, h);
}

void draw() {
drawBall(x, y, 10, 10);
}

Sketch #1:

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.

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 [2]:
// Global variables:
// defined here, used in setup() and draw()

float x;
float y;

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

void drawBall(float x, float y, int w, int h) {
fill(255, 0, 0);
ellipse(x, y, 10, 10);
}

void draw() {
drawBall(x, y, 10, 10);
x += random(2) - 1;
y += random(2) - 1;
}

Sketch #2:

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 [3]:
// Global variables:
// defined here, used in setup() and draw()

float x;
float y;

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

void drawBall(float x, float y, int w, int h) {
fill(255, 0, 0);
ellipse(x, y, 10, 10);
}

void draw() {
background(168);
drawBall(x, y, 10, 10);
x += random(2) - 1;
y += random(2) - 1;
}

Sketch #3:

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 [4]:
// 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 = -1.0;
}

void drawBall(float x, float y, int w, int h) {
fill(255, 0, 0);
ellipse(x, y, 10, 10);
}

void draw() {
float dx = vx * dt;
x = x + dx;

float dy = vy * dt;
y = y + dy;

drawBall(x, y, 10, 10);

t = t + dt;
}

Sketch #4:

Somewhat interesting... but where did it go?

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.

In [5]:
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 = 70.0;
vy = 5.0;
}

void drawBall(float x, float y, int w, int h) {
fill(255, 0, 0);
ellipse(x, y, 10, 10);
}

void draw() {
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, 10, 10);

t = t + dt;
}

Sketch #5:

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 [6]:
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, int w, int h) {
fill(255, 0, 0);
ellipse(x, y, 10, 10);
}

void draw() {
// 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, 10, 10);

t = t + dt;
}

Sketch #6:

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 [7]:
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, int w, int h) {
fill(255, 0, 0);
ellipse(x, y, 10, 10);
}

void draw() {
// gravity
background(255);
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, 10, 10);

t = t + dt;
}

Sketch #7:

Interactivity¶

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

In [8]:
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, int w, int h) {
fill(255, 0, 0);
ellipse(x, y, 10, 10);
}

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, 10, 10);

t = t + dt;
}

void mousePressed() {
x = mouseX;
y = mouseY;
vx = 0.0;
vy = 0.0;
}

Sketch #8:

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 [9]:
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, int w, int h) {
fill(255, 0, 0);
ellipse(x, y, w, h);
}

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;
//drawBall(x, y, int(vy), 5);
//noLoop();
//return;
} else {
y = y + dy;
}

drawBall(x, y, 10, 10);

t = t + dt;
}

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

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

void mouseDragged() {
background(255);
drawBall(x, y, 10, 10);
line(x, y, mouseX, mouseY);
}

Sketch #9: