Ball Inheritance

The BallInheritance activity explores inheritance, superclasses, and subclasses in the context of a Ball class that will be used to model the motion of a graphical ball on the screen.

The completed activity should be compressed as BallInheritance.zip and uploaded to the server.

Part 1 - The Ball class

A Ball class describes a model of a 2-dimensional ball, with a radius, x position, y position, and velocities vX and vY in the x- and y-directions.

Write the Ball class, with a constructor that takes those five values as parameters, along with getters and setters for those instance variables.

The move method for the Ball class takes a float parameter t that represents a period of time that passes, and calculates the ball's new position based on physics formulae. Include this method in your class.

/** 
 * The move method calculates new x- and y-positions based
 * on the current positions, the velocity in each direction,
 * and an amount of time t that has passed (standard physics
 * calculations).
 * @param t a float that indicates an amount of time
 */
public void move(float t)
{
    x = x + vX * t;
    y = y + vY * t;
}

Additionally, write a toString method that identifies the state of the ball in the format

Ball[r=30.0,x=455.2798,y=386.9585,vX=0.1,vY=0.7]

Part 2 - BallInheritance and the Processing environment

We'd like to actually be able to see the ball moving on a screen. Although Java has its own graphics libraries, we're going to use the Processing environment to:

  1. Write a main program
  2. Include the Ball class that we've just written in the project
  3. Write additional classes that inherit from the Ball class

2.1. Create a Processing project and write the main setup and draw methods.

The main project file is given here. Put this into the first tab of a new Processing project called BallInheritance.

/**
 * The Ball Inheritance project demonstrates object-oriented
 * programming and inheritance in the context of balls moving
 * around on a Processing graphical window.
 */

///////////////////////////////////////////////////////////
// Global variables for the main program declared here
///////////////////////////////////////////////////////////

BouncingBall b;             // A single instance of the Ball class
float deltaT;               // a time-interval for moving the ball
boolean launched;           // true if the ball has been launched
PVector p0, p1;             // Two PVector points, used just at
                            // beginning to identify direction. Each
                            // point has instance variables x,y

///////////////////////////////////////////////////////////
// Global variables and the Processing window initialized
///////////////////////////////////////////////////////////

void setup()
{
    size(900, 700);       // the size of the graphical window
    background(255);      // background color is white
    b = new BouncingBall(30, width/2, height/2, 0, 0);   
    deltaT = 0.3;         // An arbitrary time period
    launched = false;     // flag turns true when ball is launched
}

///////////////////////////////////////////////////////////
// Additional functions to handle interactions with mouse
// (used for launching the ball)
///////////////////////////////////////////////////////////

/**
* Processing function to identify when mouse is pressed.
* Here, first click is captured for "drawing back the bowstring"
*/
void mousePressed()
{
    p0 = new PVector(mouseX, mouseY);
}

/**
* Processing function to identify when "bowstring is released,"
* launching the ball.
*/
void mouseReleased()
{
    p1 = new PVector(mouseX, mouseY);
}

////////////////////////////////////////////////////////////////////////
////////////////////////  Main draw() loop  ////////////////////////////
////////////////////////////////////////////////////////////////////////

void draw()
{
    background(255);             // Clear the screen each time
    if (launched)                 
    {
        b.display();               
        println(b);                // displays ball state in console
        b.move(deltaT);            // changes ball state
    }
    else                         // ball hasn't been launched yet
    {
        // We'll click-drag a line, where the direction of the line
        // indicates the direction of the launch, and the magnitude
        // represents the intial velocity of the launch
        if (p0 != null)    // If we've clicked to start bowstring pull
        {
            if (p1 == null)  // If we haven't released the mouse...
            {
                line(p0.x, p0.y, mouseX, mouseY);   // draw to the mouse location
                                                    // (so we can aim)
            }
            else                                  // We've released the mouse!
            {
                b.setVx( (p0.x - p1.x)/10 );        // Set the ball's initial velocity
                b.setVy( (p0.y - p1.y)/10 );        // in x and y directions as a function
                launched = true;                    // of how far the bowstring was pulled
                                                    // back.
            }
        }  
    }
}

2.2. Include the Ball class in your project

In the Processing project, open up a new tab where we can put in our Ball class.

You may have noticed that the draw loop calls a display() method for the ball object, and we haven't written that method yet.

Modify the Ball class to include a display method that calls Processing's ellipse() function to draw the ball at its current position in the graphical window. Note that the ellipse takes x- and y-diameters as parameters, so doubling the radius is required to draw the ball the correct size.

Run and debug your project.

2.3. Write additional classes that inherit from Ball

Having the ball disappear off the screen is not very interesting. If you look at the Processing console, you can see that the ball is still moving through space. It's just that we can't see it in the window we're looking at.

2.3.1. WrapperBall

Write a WrapperBall class that inherits from Ball. A WrapperBall object is a type of ball, but it wraps around the screen: if it moves off the bottom of the screen it reappears at the top, or if it moves off the right side of the screen it reappears on the left, etc.

Which methods from the superclass Ball can we use unmodified? Which methods from the superclass will we need to override for this class? Do we need to write any additional methods that will only be used by WrapperBall?

Modify your BallInheritance main program to test this new type of ball.

2.3.2. BouncingBall

Write a BouncingBall class that inherits from Ball. This class bounces off the edges of the screen.

2.4. Create a MultiBall Project

Using any of the classes that you've created, create a new project called MultiBall in which the runner creates an Array or ArrayList of WrapperBall or BouncingBall objects and displays them all on the screen.

2.5 Implement gravity for a BouncingBall

Modify your BouncingBall class so that the balls in the project are subject to the force of gravity. Do you need to modify the Ball class to do this? (You shouldn't!) Do you need to modify the BouncingBall class to do this? (Possibly?) Or maybe you can write a GravityBall class that inherits from BouncingBall? This may or may not be possible, depending on how you've written the original BouncingBall.