Example: A Ball that Bounces and Pulses¶
In these notes you will learn:
- How to make a bouncing ball become bigger and smaller as it moves.
- How to prevent the ball from getting “stuck” in an edge.
Introduction¶
In these notes we are going to being with the following program that makes a ball bounce around the screen:
float x; // (x, y) is the center of the ball
float y;
float dx; // speed along x-axis
float dy; // speed along y-axis
void setup() {
size(500, 500);
x = 250;
y = 250;
dx = 1.5;
dy = -3.5;
smooth();
fill(255, 0, 0);
noStroke();
}
void draw() {
background(255);
ellipse(x, y, 100, 100);
x += dx;
y += dy;
// check if hit top edge
if (y - 50 < 0) {
dy = -dy;
}
// check if hit bottom edge
if (y + 50 > 499) {
dy = -dy;
}
// check if hit right edge
if (x + 50 > 499) {
dx = -dx;
}
// check if hit the left edge
if (x - 50 < 0) {
dx = -dx;
}
}
Our goal here is to add a neat new effect to this program: we want the ball to pulse, i.e. continuously get smaller and bigger as it bounces around the screen.
Adding a Diameter Variable¶
The first thing we’ll do is add a float
variable called diam
that
represents the diameter of the ball:
float x; // (x, y) is the center of the ball
float y;
float dx; // speed along x-axis
float dy; // speed along y-axis
float diam;
void setup() {
size(500, 500);
x = 250;
y = 250;
dx = 1.5;
dy = -3.5;
diam = 100;
smooth();
fill(255, 0, 0);
noStroke();
}
void draw() {
background(255);
ellipse(x, y, diam, diam);
x += dx;
y += dy;
// check if hit top edge
if (y - diam / 2 < 0) {
dy = -dy;
}
// check if hit bottom edge
if (y + diam / 2 > 499) {
dy = -dy;
}
// check if hit right edge
if (x + diam / 2 > 499) {
dx = -dx;
}
// check if hit the left edge
if (x - diam / 2 < 0) {
dx = -dx;
}
}
Notice that we:
- initialized
diam
too 100 insetup()
- changed the circle-drawing statement to
ellipse(x, y, diam, diam)
- changed the condition of all the if-statements to use
diam / 2
instead of 50
Be sure to test your program after making this change to make sure it worked correctly. The behaviour should be exactly the same as before.
Adding a Diameter Speed Change¶
We want the ball’s diameter to grow smalle and bigger at some constant rate,
and so we will add another variable, called ddiam
, that represents by how
many pixels the diameter of the ball will change on each call to draw()
:
float x; // (x, y) is the center of the ball
float y;
float dx; // speed along x-axis
float dy; // speed along y-axis
float diam;
float ddiam; // speed at which diameter changes
void setup() {
size(500, 500);
x = 250;
y = 250;
dx = 1.5;
dy = -3.5;
diam = 100;
ddiam = -1; // diameter starts getting smaller
smooth();
fill(255, 0, 0);
noStroke();
}
void draw() {
background(255);
ellipse(x, y, diam, diam);
x += dx;
y += dy;
diam += ddiam;
if (diam < 20) { // if the diameter is too small,
ddiam = -ddiam; // flip ddiam's sign so the diam gets bigger
}
if (diam > 100) { // if the diameter is too big,
ddiam = -ddiam; // flip ddiam's sign the diam gets smaller
}
// check if hit top edge
if (y - diam / 2 < 0) {
dy = -dy;
}
// check if hit bottom edge
if (y + diam / 2 > 499) {
dy = -dy;
}
// check if hit right edge
if (x + diam / 2 > 499) {
dx = -dx;
}
// check if hit the left edge
if (x - diam / 2 < 0) {
dx = -dx;
}
}
Here’s the changes from the previous program:
- the
float
ddiam
has been added to represent the rate at which the ball’s diameter changes - in
setup()
,ddiam
is initialized to -1 so that the ball is initially shrinking - in
draw()
, we added the statementdiam += ddiam
to update the size of the ball’s diameter after ew draw it - again in
draw()
, we added two if-statements to check to flip the sign ofddiam
when the ball gets either too small or too big
When you run this program it may appear, initially, that it works correctly. However, you should soon see an obvious bug: the ball sometimes gets in the edges.
Fixing the Edge Bug¶
The previous program doesn’t always work correctly. The problem is that, sometimes, the ball goes past an edge and gets stuck. For example, if the top- most point of the ball goes past the top edge, then even though the direction of the ball changes, the top-most point of the ball is still off the edge.
This is a tricky and subtle problem. We’ll deal with by cheating a little: whenever we detected that the ball has hit an edge, we’ll move back onto the screen to make sure that it doesn’t get caught in an edge.
float x; // (x, y) is the center of the ball
float y;
float dx; // speed along x-axis
float dy; // speed along y-axis
float diam;
float ddiam;
void setup() {
size(500, 500);
x = 250;
y = 250;
dx = 1.5;
dy = -3.5;
diam = 100;
ddiam = -1;
smooth();
fill(255, 0, 0);
noStroke();
}
void draw() {
background(255);
ellipse(x, y, diam, diam);
x += dx;
y += dy;
diam += ddiam;
if (diam < 20) {
ddiam = -ddiam;
}
if (diam > 100) {
ddiam = -ddiam;
}
// check if hit top edge
if (y - diam / 2 < 0) {
y = diam / 2;
dy = -dy;
}
// check if hit bottom edge
if (y + diam / 2 > 499) {
y = 499 - diam / 2;
dy = -dy;
}
// check if hit right edge
if (x + diam / 2 > 499) {
x = 499 - diam / 2;
dx = -dx;
}
// check if hit the left edge
if (x - diam / 2 < 0) {
x = diam / 2;
dx = -dx;
}
}
The edge-detection if-statements now all have this form:
- if the ball has hit the edge then
- reset the position of the ball so it is entirely on the screen flip the sign of the appropriate d-variable
This is important! Just changing the d-variable is not enough because it doesn’t stop the ball from getting stuck in an edge.
Questions¶
Modify the bouncing ball program so that a small ellipse is drawn under the ball as a shadow to give the illusion of 3-dimensions. For example:
Make sure the shadow gets bigger as the ball’s size increases.
Modify the bouncing ball program so that when the ball hits the left edge of the screen, its speed increases by a factor of 1.5.
Also, keep the ball’s size fixed: do not have it change size when it hits an edge.
Write a program that makes a square bounce around the screen. When the squares hits an edge it should hit the edge exactly, without any part of it going off the screen.
Write a program that makes a
PImage
bounce around the screen. When the image hits an edge it should hit the edge exactly, without any part of it going off the screen.Modify the bouncing ball program so that the ball changes to red when it hits the top edge; to green when it hits the right edge; to blue when it hits the bottom edge; and to orange when it hits the left edge.
Draw a 200-by-200 square centered in the middle of a 500-by-500 screen. Write a program that makes a ball bounce inside this square.
Make two different colored balls bounce around the screen. You’ll need to keep track of the position and velocity of each ball, so your program will need at least 8 different variables.
Modify the bouncing ball program so that the ball’s diameter does not change when it hits an edge. Instead, use the
map
function to make the balls diameter go from 25 to 150 as the mouse pointer moves horizontally across the screen.For example, when the mouse pointer is halfway across the screen, the ball should have a diameter of about 87 (i.e. halfway between 25 and 150). When the mouse pointer is at the very left of the screen, the ball’s diameter should be 25.
Modify the bouncing ball program so that every fifth time the ball hits any edge it changes color. For example, it can start out orange, and the after 5 edge hits it turns red. Then after 5 more edge hits it turns red, and so on.
Also, keep the ball’s size fixed: do not have it change size when it hits an edge.
Code: The Bouncing Ball Program¶
float x; // (x, y) is the center of the ball
float y;
float dx; // speed along x-axis
float dy; // speed along y-axis
float diam;
float ddiam;
void setup() {
size(500, 500);
x = 250;
y = 250;
dx = 1.5;
dy = -3.5;
diam = 100;
ddiam = -1;
smooth();
fill(255, 0, 0);
noStroke();
}
void draw() {
background(255);
ellipse(x, y, diam, diam);
x += dx;
y += dy;
diam += ddiam;
if (diam < 20) {
ddiam = -ddiam;
}
if (diam > 100) {
ddiam = -ddiam;
}
// check if hit top edge
if (y - diam / 2 < 0) {
y = diam / 2;
dy = -dy;
}
// check if hit bottom edge
if (y + diam / 2 > 499) {
y = 499 - diam / 2;
dy = -dy;
}
// check if hit right edge
if (x + diam / 2 > 499) {
x = 499 - diam / 2;
dx = -dx;
}
// check if hit the left edge
if (x - diam / 2 < 0) {
x = diam / 2;
dx = -dx;
}
}