A Bouncing Ball Sprite

In these notes you will learn:

  • How to create a class that animates a bouncing ball based on the Sprite class.
  • How to create randomly initialized bouncing balls.

A Bouncing Ball

A ball that bounces around the screen has been one of our key examples in this course. So here we re-write it use the Sprite class:

class Sprite {
  float x;
  float y;
  float dx;
  float dy;

  void update() {
    x += dx;
    y += dy;
  }
}

class BouncingBall extends Sprite {
  float diam;
  color fillColor;

  void render() {
    pushMatrix();

    noStroke();
    fill(fillColor);

    ellipse(x, y, diam, diam);

    popMatrix();
  }

  void update() {
    x += dx;
    y += dy;

    // hit top?
    if (y - diam / 2 < 0) {
      y = diam / 2;
      dy = -dy;
    }

    // hit bottom?
    if (y + diam / 2 > height) {
      y = height - diam / 2;
      dy = -dy;
    }

    // hit left?
    if (x - diam / 2 < 0) {
      x = diam / 2;
      dx = -dx;
    }

    // hit right?
    if (x + diam / 2 > width) {
      x = width - diam / 2;
      dx = -dx;
    }
  }
}

BouncingBall ball = new BouncingBall();

void setup() {
  size(500, 500);

  ball.x = 250;
  ball.y = 250;
  ball.dx = -1.2;
  ball.dy = 2.5;
  ball.diam = 50;
  ball.fillColor = color(0, 0, 255);
}

void draw() {
  background(255);

  ball.update();
  ball.render();
}

An important detail to notice here is that the BouncingBall class overrides the update() function from Sprite. That means that BouncingBall provides its own implementation of update() and ignores the one in Sprite.

Multiple Bouncing Balls

With the BouncingBall class written, it is now relatively easy to create multiple bouncing balls. For example:

BouncingBall b1 = new BouncingBall();
BouncingBall b2 = new BouncingBall();
BouncingBall b3 = new BouncingBall();

void setup() {
  size(500, 500);

  b1.x = 250;
  b1.y = 250;
  b1.dx = -1.2;
  b1.dy = 2.5;
  b1.diam = 50;
  b1.fillColor = color(0, 0, 255);

  b2.x = 150;
  b2.y = 250;
  b2.dx = 1.2;
  b2.dy = 3.5;
  b2.diam = 75;
  b2.fillColor = color(255, 0, 0);

  b3.x = 250;
  b3.y = 250;
  b3.dx = 1.2;
  b3.dy = 1.5;
  b3.diam = 150;
  b3.fillColor = color(0, 255, 0);
}

void draw() {
  background(255);

  b1.update();
  b1.render();

  b2.update();
  b2.render();

  b3.update();
  b3.render();
}

As you can see, initializing all the variables of the BouncingBall object takes a lot of code. Lets see one way to simplify that.

Random Bouncing Balls

Processing has a built-in function called random that generates random numbers. For example, random(65) returns a random number that is greater than, or requal to 0, and less than (but never equal to!) 65:

println(random(65));  // prints 33.455647
println(random(65));  // prints 45.825603
println(random(65));  // prints 49.4932

You can also call random with a low value and a high value like this:

println(random(10, 20)); // 13.474632
println(random(10, 20)); // 18.421371
println(random(10, 20)); // 11.419113

Lets use random to create a ball with randomly chosen initial values:

BouncingBall ball = new BouncingBall();

void setup() {
  size(500, 500);

  ball.x = random(100, 200);
  ball.y = random(100, 200);
  ball.dx = random(-3, 3);
  ball.dy = random(-3, 3);
  ball.diam = random(50, 150);
  ball.fillColor = color(random(255),
                         random(255),
                         random(255));

}

void draw() {
  background(255);

  ball.update();
  ball.render();
}

Every time you run this program you get a different ball.

To create more than one random ball, we need to call the initialization code for each BouncingBall object. That’s a lot of code and soon gets tedious, so a better idea is to create a function that creates a random BouncingBall for us:

BouncingBall randomBouncingBall() {
  BouncingBall ball = new BouncingBall();
  ball.x = random(100, 200);
  ball.y = random(100, 200);
  ball.dx = random(-3, 3);
  ball.dy = random(-3, 3);
  ball.diam = random(50, 150);
  ball.fillColor = color(random(255),
                         random(255),
                         random(255));
  return ball;
}

BouncingBall b1;  // no need to call new BouncingBall() here
BouncingBall b2;  // because that's done for us in the
BouncingBall b3;  // randomBouncingBall() function

void setup() {
  size(500, 500);

  b1 = randomBouncingBall();
  b2 = randomBouncingBall();
  b3 = randomBouncingBall();
}

void draw() {
  background(255);

  b1.update();
  b1.render();

  b2.update();
  b2.render();

  b3.update();
  b3.render();
}

Every time you run this program, you get three different bouncing balls. Plus creating and initializing the balls is much less work.

100 Bouncing Balls?

Three bouncing balls are nice, but how could we make 100 balls bounce around the screen? If you think about this for a moment, you will realize that if we have 100 balls, we’ll need 100 variables, e.g.:

BouncingBall ball1;
BouncingBall ball2;
BouncingBall ball3;
// ...
BouncingBall ball100;

void setup() {
   size(500, 500);
   smooth();
   ball1 = randomBouncingBall();
   ball2 = randomBouncingBall();
   ball3 = randomBouncingBall();
   // ...
   ball100 = randomBouncingBall();
}

void draw() {
  background(255);

  ball1.render();
  ball1.update();

  ball2.render();
  ball2.update();

  ball3.render();
  ball3.update();

  // ...

  ball100.render();
  ball100.update();
}

This program will work, but it is far too much typing. Plus, if we wanted, say, 200 or 300 balls, then even more typing is needed.

This is clearly impractical. In the next set of notes we’ll see a solution to this problem.

Questions

  1. What’s the smallest integer value that random(1, 10) can return? The biggest?

Programming Questions

  1. Modify the randomBouncingBall function so that the alpha value of the color is also set randomly. Test it in the bouncing balls program from the notes.
  2. Create a new class called WraparoundBall that is similar to BouncingBall, except when it hits and edge it immediately “jumps” to the other edge.

Code

class Sprite {
  float x;
  float y;
  float dx;
  float dy;

  void update() {
    x += dx;
    y += dy;
  }
}

class BouncingBall extends Sprite {
  float diam;
  color fillColor;

  void render() {
    pushMatrix();

    noStroke();
    fill(fillColor);

    ellipse(x, y, diam, diam);

    popMatrix();
  }

  void update() {
    x += dx;
    y += dy;

    // hit top?
    if (y - diam / 2 < 0) {
      y = diam / 2;
      dy = -dy;
    }

    // hit bottom?
    if (y + diam / 2 > height) {
      y = height - diam / 2;
      dy = -dy;
    }

    // hit left?
    if (x - diam / 2 < 0) {
      x = diam / 2;
      dx = -dx;
    }

    // hit right?
    if (x + diam / 2 > width) {
      x = width - diam / 2;
      dx = -dx;
    }
  }
}

BouncingBall randomBouncingBall() {
  BouncingBall ball = new BouncingBall();
  ball.x = random(100, 200);
  ball.y = random(100, 200);
  ball.dx = random(-3, 3);
  ball.dy = random(-3, 3);
  ball.diam = random(50, 150);
  ball.fillColor = color(random(255),
  random(255),
  random(255));
  return ball;
}

BouncingBall b1;  // no need to call new BouncingBall() here
BouncingBall b2;  // because that's done for us in the
BouncingBall b3;  // randomBouncingBall() function

void setup() {
  size(500, 500);

  b1 = randomBouncingBall();
  b2 = randomBouncingBall();
  b3 = randomBouncingBall();
}

void draw() {
  background(255);

  b1.update();
  b1.render();

  b2.update();
  b2.render();

  b3.update();
  b3.render();
}