Introduction
In this assignment you will use object-oriented design to build on the work you have already completed in Assignment 1. Namely, now that you have implemented the simulation of a single ballistic ball with a simple physics model, you will leverage your existing code to allow adding multiple balls to the simulation. As stated in the chapter on Objects and Classes in the Roberts text book The Art and Science of Java, the “idea of thinking of parts of your programs as black boxes is fundamental to the concept of object-oriented programming”. Thus, you can design your program such that the code determining the trajectory of a ball resides within the “black box” of a ball class; you can then create (instantiate) as many balls as you want (with different initial parameters), and these balls can move separately based on the given initial parameters. For this assignment, you will rely heavily on concepts in Chapters 5 and 6 in the textbook, as well as the previous chapters.
Problem Description
The goal of this assignment is to build a simulation for 100 balls with randomly chosen parameters. All balls are launched from the same X coordinate (center of the field) with initial height corresponding to ball radius. Figure 1 shows several snapshots from a video sequence generated by this simulation.
Figure 1 – a sequence of 3 frames from a video of the simulation sequence.
At minimum, you will need at least 2 classes for this simulation, the aBall class which generates an instance of ball in motion according to Assignment 1, and the bSim class which sets up the display, generates parameters and an instance of each ball, and runs until terminated by the user.
The first task is to design the aBall class according to the following constructor:
public aBall (double Xi, double Yi, double Vo, double theta, double bSize, Color bColor, double bLoss) where
Xi:
is the X coordinate of the initial launch position (meters)
Yi:
is the Y coordinate of the initial launch position (meters)
Vo:
is the initial launch velocity (meters/second)
theta:
is the initial launch angle (degrees, as measured from the ground plane)
bSize:
the radius of the ball (meters)
bColor:
ball color
bLoss:
energy loss coefficient
This class essentially encapsulates the code you wrote for Assignment 1.
The second task is to write the bSim class which randomly generates the parameters for 100 separate balls. The parameters used by this class are summarized below.
private static final int WIDTH = 1200;
private static final int HEIGHT = 600; private static final int OFFSET = 200;
// n.b. screen coordinates
private static final double SCALE = HEIGHT/100;
// pixels per meter
private static final int NUMBALLS = 100;
// # balls to simulate
private static final double MINSIZE = 1.0;
// Minumum ball radius (meters)
private static final double MAXSIZE = 10.0;
// Maximum ball radius (meters)
private static final double EMIN = 0.1;
// Minimum loss coefficient
private static final double EMAX = 0.6;
// Maximum loss coefficient
private static final double VoMIN = 40.0;
// Minimum velocity (meters/sec)
private static final double VoMAX = 50.0;
// Maximum velocity (meters/sec)
private static final double ThetaMIN = 80.0;
// Minimum launch angle (degrees)
private static final double ThetaMAX = 100.0;
// Maximum launch angle (degrees)
Designing the aBall class
The aBall class must do the following:
1. Create an instance of a GOval from the specified parameters (constructor). Further, since we need to add this object to the display, a corresponding get method needs to be included, i.e., getBall();.
2. Once the instance is generated, the simulation loop is run until the ball runs out of steam. Since messages are sent to the GOval inside of aBall, the ball will animate automatically until the simulation terminates. Most of the code you wrote in Assignment 1 can be copied with little change.
3. Since we want each ball to move independently, the corresponding objects must run concurrently. Although this is well beyond the scope of an introductory course, Java makes it very easy to make objects run concurrently. All that is required is for the aBall to extend the thread class.
You can find out more about the thread class here:
https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html).
The concept of threading will be very important for your later courses (especially Design Principles and Methods, ECSE 211) and allows your application to have multiple threads of execution running concurrently.
Design Approach
Let us first consider the aBall class, the template for which is shown below (you are to use this template in designing your implementation:
public class aBall extends Thread {
/**
* The constructor specifies the parameters for simulation. They are *
* @param Xi double The initial X position of the center of the ball
* @param Yi double The initial Y position of the center of the ball
* @param Vo double The initial velocity of the ball at launch
* @param theta double Launch angle (with the horizontal plane)
* @param bSize double The radius of the ball in simulation units
* @param bColor Color The initial color of the ball
* @param bLoss double Fraction [0,1] of the energy lost on each bounce */
public aBall(double Xi, double Yi, double Vo, double theta, double bSize, Color bColor, double bLoss) {
this.Xi = Xi; // Get simulation parameters
this.Yi = Yi; this.Vo = Vo; this.theta = theta; this.bSize = bSize; this.bColor = bColor;
this.bLoss = bLoss;
/**
* The run method implements the simulation loop from Assignment 1.
* Once the start method is called on the aBall instance, the
* code in the run method is executed concurrently with the main * program.
* @param void
* @return void
*/
public void run() {
// Simulation goes here...
}
}
Example:
Using the aBall class, create a simulation for a single ball, initially located at coordinates (simulation, not screen) (10,100), with size=6, Color=Red, loss coefficient=0.25, with an initial velocity of 1.0 m/s. at an angle of 30°.
//
// Code to set up the graphics environment as per Assignment 1
// goes here
//
aBall redBall = new aBall(10.0,100.0,1.0,30.0,6.0,Color.RED,0.25); add(redBall.getBall()); redBall.start();
Details:
Inside the constructor of the aBall class, an instance of GOval corresponding to a filled circle is instantiated as follows:
myBall = new GOval(paramaters); myBall.setFilled(true);
myBall.setFillColor(parameter);
To make the resulting GOval accessable outside of aBall, we add an appropriate “getter” as follows:
public GOval getBall() { return myBall;
}
Since aBall is an extension of the Thread class, it inherits the corresponding methods – one of which is “start”. The effect of calling the start method on the aBall class instance is to call the run method associated with aBall. However, there is an important side effect to this method call. Rather than returning when the method has completed, it returns immediately, allowing the method to run concurrently with the calling program. In other words, the simulation embedded within the aBall instance runs in parallel with the main program and all other instances of the aBall class.
Another problem that we have to deal with is that we no longer have access to the pause method, used to control the speed at which the display is updated. Fortunately the Thread class includes a method called “sleep” which takes an argument of type long expressing the delay in milliseconds. We haven’t dealt with exceptions yet, so just include the following pattern in place of pause to achieve the same effect.
try { // pause for 50 milliseconds
Thread.sleep(50);
} catch (InterruptedException e) { e.printStackTrace();
}
For reasons that will become clear in later courses, the sleep duration for the aBall thread should be half as long as the time step. For example, if time is updated every 100 mS (0.1 S), then the sleep duration (above) should be half of that (50 mS).
One more detail regarding the aBall class – stopping. When the while loop is exited, the run method terminates which results in the thread terminating. For the while loop to continue running, two conditions must be met:
1. The total energy (KEx+KEy) must be greater than some minimum energy ETHR.
AND
2. The total energy must be less than it was on the previous bounce.
The effect of terminating the thread is that no further messages are sent to its corresponding ball, i.e., it stops moving.
To complete this program, we need a main class which must correspond to the template below:
public class bSim extends GraphicsProgram {
// Parameters used in this program
public void run() {
// Set up display, create and start multiple instances of aBall
}
}
Your main program should set up the display as in Assignment 1. The screen is laid out as a 1200 x 800 rectangle, with the ground plane sitting at 600 (offset of 200). You will run your final simulation with 100 balls (although for debugging purposes it is suggested that you use smaller values, e.g., 1). The aBall constructor needs 7 parameters – Xi, Yi, Vo, theta, bSize, bColor, and bLoss. Use the RandomGenerator class shown in the slides to generate values for each aBall instance. For example, to generate a random loss parameter, one would use an instance of the RandomGenerator class as follows:
double iLoss = rgen.nextDouble(EMIN,EMAX);
Finally, to generate a simulation with NUMBALLS elements, one can easily set up a for loop that on each iteration generates a new set of random parameters, creates a aBall instance using these parameters, and starting the corresponding thread.
You might also consider writing a “helper” class with utility functions, e.g. methods for converting from simulation coordinates to screen coordinates, etc. Although this is not strictly required, it does make your code a lot easier to read and understand.
Instructions
1. Write Java classes, bSim.java, aBall.java, and gUtil.java (optionally), that implement the simulation outlined above. If you wish to implement using more classes than these three, you can do so. Do this within the Eclipse environment so that it can be readily tested by the course graders. For your own benefit, you should get in the habit of naming your Eclipse projects so that they can easily be identified, e.g., ECSE202_A2.
2. Edit the parameters of bSim to replicate the output of Assignment 1, i.e., generate a single aBall instance with Xi=5m, Yi=1m, Vo=40 m/s, theta=85°, loss=0.4, radius=1m. Verify that it traces the identical path to the bounce class. Take a snapshot of the screen when the simulation reaches steady-state and save as A2-1.pdf.
3. Repeat Question 2, but this time with parameters Xi=95m, Yi=1m, Vo=40 m/s, theta=95°, loss=0.4, radius=1m. Verify that the path is identical to Question 2, except that the ball moves from right to left. Take a snapshot of the screen when the simulation reaches steady-state and save as A2-2.pdf.
4. Perform a simulation with 100 balls using the parameters listed on Page 2. In order for us to validate your simulation we need a means to ensure that all simulations produce identical results. After creating a the random number generator object do the following: rgen.setSeed((long) 0.12345);
This will produce the same sequence of psuedo random numbers for each program run, terminating at exactly the same state. Take a snapshot of the screen when the simulation reaches steady-state and save as A2-3.pdf.