Assignment 2 - Thomy-G/BIU_OOP_2025B GitHub Wiki

Objects, Geometry, Abstract Art and Bouncing Balls

In this assignment you will continue working with Objects. You will define Classes and instantiate objects of those classes. The code in this assignment will be used in later assignments.

First, please read about working with multiple classes: MultFiles.

We supply this build.xml for the assignment. Recommendation: read the entire assignment before you start writing it.

Important Note

In this course, your plan should simply just work. Just like real programmers, you need to think about odd edge cases that might occur - nothing should cause your program to crash. It is your responsibility to deal with these edge cases.

Open your mind - in this assignment (and the following assignments), we provide you with some classes and methods which are obligatory in your implementation; but it is very likely that you need to implement other classes and methods to complete the assignment. Good design is key to your success in these assignments.

Signatures of methods must not be changed!

Don't forget JAVADOC

Animation and Bouncing Balls

You will draw balls (which are circles) and move them across the screen.

What to submit?

You need to include all the classes defined below.

The target ant run2 will run the BouncingBallAnimation class, and ant run3 will run the MultipleBouncingBallsAnimation class.

Task 1: Static Balls which you can draw.

Our main object will be a Ball (actually, a circle). Balls have size (radius), color, and center (a Point). Balls also know how to draw themselves on a DrawSurface.

You need to create a Ball class, with at least the following methods:

public class Ball {
   // constructor
   public Ball(Point center, int r, java.awt.Color color);

   // accessors
   public int getX();
   public int getY();
   public int getSize();  // get radius
   public java.awt.Color getColor();

   // draw the ball on the given DrawSurface
   public void drawOn(DrawSurface surface);
}

Note: class Point operates with double and class Ball operates with int, you are allowed to use casting from double to int. Signatures of methods of class Point should not be changed due to automatic checks.

You can test your code with the following program, which will create 3 balls and show them on the screen.

import biuoop.GUI;
import biuoop.DrawSurface;

import java.awt.Color;


public class BallsTest1 {
   public static void main(String[] args) {
      GUI gui = new GUI("Balls Test 1", 800, 600);
      DrawSurface d = gui.getDrawSurface();
      
      Ball b1 = new Ball(100, 100, 30, Color.RED);
      Ball b2 = new Ball(100, 150, 10, Color.BLUE);
      Ball b3 = new Ball(80, 249, 50, Color.GREEN);

      b1.drawOn(d);
      b2.drawOn(d);
      b3.drawOn(d);

      gui.show(d);
   }
}

Note: we do not provide you with the build commands or an Ant target for this testing code - you should handle it yourself!

Task 2: A simple animation loop with one ball

Animation is achieved by drawing different pictures on the same area one after the other. Using our graphical package, we can do animation using a loop such as the following:

import biuoop.Sleeper

import java.util.Random

   static private void drawAnimation() {
      GUI gui = new GUI("title", 800, 600);
      Sleeper sleeper = new Sleeper();
      Random rand = new Random();
      while (true) {
         DrawSurface d = gui.getDrawSurface();
         Ball ball = new Ball(rand.nextInt(800), rand.nextInt(600), 30, Color.BLACK);
         ball.drawOn(d);
         gui.show(d);
         sleeper.sleepFor(50);  // wait for 50 milliseconds.
      }
   }   

You can call this method from your main method and run it.

Each iteration of the loop creates an empty drawing surface, creates a ball with a random location, draws it on the surface, shows the surface and waits for 50 milliseconds. Assuming that creating the surface and displaying the ball take roughly zero time, sleeping for 50 milliseconds gets us almost 20 frames per second.

The animation is not really good -- things seem to jump all over the place. The problem is that the different frames are not related to each other.

Lets fix that and create an animation with a moving ball. In order to do that, we need to give our ball some speed and direction. The first step would be to define a Velocity class:

// Velocity specifies the change in position on the `x` and the `y` axes.
public class Velocity {
   // constructor
   public Velocity(double dx, double dy);

   // Take a point with position (x,y) and return a new point
   // with position (x+dx, y+dy)
   public Point applyToPoint(Point p);
}

Next, we add a Velocity field, as well as the following methods, to the Ball class:

public void setVelocity(Velocity v);
public void setVelocity(double dx, double dy);
public Velocity getVelocity();

public void moveOneStep() {
    this.center = this.getVelocity().applyToPoint(this.center);
}

And change the animation code from above to:

   static private void drawAnimation(Point start, double dx, double dy) {
      GUI gui = new GUI("title", 800, 600);
      Sleeper sleeper = new Sleeper();
      Ball ball = new Ball(start.getX(), start.getY(), 30, Color.BLACK);
      ball.setVelocity(dx, dy);
      while (true) {
         ball.moveOneStep();
         DrawSurface d = gui.getDrawSurface();
         ball.drawOn(d);
         gui.show(d);
         sleeper.sleepFor(50);  // wait for 50 milliseconds.
      }
   }

(question: what happens if we do not invoke setVelocity before the loop? make sure the program does not crash!)

This is much better! But the animation is over very quickly, because the ball goes outside of the screen. Change the moveOneStep() method so that the ball does not go outside of the screen -- when it hits the border to the left or to the right, it should change its horizontal direction, and when it hits the border on the top or the bottom, it should change its vertical direction. (Changing the horizontal direction can be achieved by setting the velocity's dx to -dx).

Note: big enough Velocity can cause the ball to "skip" over the border, and not bounce off it. In this assignment you can assume the velocities and ball sizes to not cause such a situation.

Create a class called BouncingBallAnimation with a main method that gets 4 integers from the command line and runs the drawAnimation method accordingly - for example, java BouncingBallAnimation 1 2 3 4 would invoke drawAnimation(new Point(1, 2), 3, 4).

Note It is convenient to specify the velocity in terms and angle and a speed, so instead of specifying dx=2, dy=0, you could specify (90, 2) meaning 2 units in the 90 degrees direction (assuming up is angle 0). This can be achieved by creating a new constructor to Velocity, taking an angle an a speed. The problem is that angle and speed are two doubles, and we already have a constructor taking two doubles (dx and dy). In order to solve this, we can create a static method (belonging to the Velocity class) that will create new instances for us, instead of the constructor:

public class Velocity {
   ...
   public static Velocity fromAngleAndSpeed(double angle, double speed) {
      double dx = ...;
      double dy = ...;
      return new Velocity(dx, dy);
   }
}

We can then use this method to create velocities:

Velocity v = Velocity.fromAngleAndSpeed(90, 2);
ball.setVelocity(v);

This method is not a suggestion. You need to implement it.

Task 3: Multiple Balls

One ball is nice, but a bit boring. We want to see many bouncing balls. In this task, you should create a program called MultipleBouncingBallsAnimation. This program is invoked from the command line, and each argument is a size of a Ball:

> java -cp biuoop-1.4.jar:bin MultipleBouncingBallsAnimation 12 2 3 4 2 9

This will create an animation with 6 balls, of sizes 12, 2, 3, 4, 2 and 9 respectively. Each ball will start in a random location on the screen. Each ball will start with a different speed -- we want larger balls to be slower (but balls above size 50 can all have the same slow speed). Each ball will change direction when hitting the window border.

Notice that the number of balls is not fixed -- use an array to store the balls.

Note: drawing multiple balls in different order might cause some of the big balls to "hide" smaller balls underneath them. Drawing balls in a specific order is not a requirement in this assignment and is up to your judgement.

Task 4: Multiple Frames

Now we want to create two frames -- one of them is a grey rectangle from (50,50) to (500,500), and the other is a yellow rectangle from (450,450) to (600,600). We want the first half of the balls to be inside the grey rectangle, and the second half of the balls to be outside both rectangles (See image to understand better).

Next assignment will go deeply in how to implement collision consistently but this time it's up to you to decide how you want to do it.

The Rectangle class will be used heavily in future assignments, it is your choice to use it now, but it will be easier to use it for frames now and repurpose it later:

public class Rectangle {

   // Create a new rectangle with location and width/height.
   public Rectangle(Point upperLeft, double width, double height);

   // Return the width and height of the rectangle
   public double getWidth();
   public double getHeight();

   // Returns the upper-left point of the rectangle.
   public Point getUpperLeft();
}

Your program should be called MultipleFramesBouncingBallsAnimation. As before, this program is invoked from the command line, and each argument is a size of a Ball:

> java -cp biuoop-1.4.jar:bin MultipleFramesBouncingBallsAnimation 12 2 3 4 2 9

Your window should look something like this: multipleFrame

As before, the number of balls is not fixed, but you can assume an even number of balls. We note that it is a much better practice to somehow handle also the case of a non-even number of balls.

Special cases and notes

  • No balls should enter the yellow frame at any given moment, balls in the gray rectangle are allowed to be "hidden" under yellow rectangle while still being within borders of the gray one(!).
  • The points you are given are not necessarily in the proper range & have the proper size, think about how to fix these edge cases. Any reasonable and consistent behavior will be accepted. It is acceptable to adjust ball radius in order to fit into the rectangle or the screen.
  • Similarly to assignment 1, you must use a threshold to compare doubles in the relevant cases.
  • Size of the window should be 800 (width) by 600 (height) in all tasks.
  • Instructions for speeds of balls being relative to their sizes are applicable to both Task 3 and Task 4
  • Exact speeds of the balls do not matter as long as they are visually reasonable for the given screen size and are relative to the ball sizes (smaller balls must be faster than larger balls). The speeds can be randomly generated.
  • Balls of size 50 or larger are considered large and can all have the same "slowest" speed.

A note on checkstyle

For this assignment, because you do not know better yet, it is OK to have the checkstyle error:

Definition of 'equals()' without corresponding definition of 'hashCode()'.

Summary

Since this assignment is based on the previous one, you also need to submit the classes like Point, Line, etc you developed in Ass1. In addition to the build.xml file, your final submission should include (at least) the following classes (in the src directory), with at least the functionality and methods as described above.

  • Ball
  • Velocity
  • BouncingBallAnimation
  • MultipleBouncingBallsAnimation
  • MultipleFramesBouncingBallsAnimation

Your build.xml includes the targets compile to compile everything, clean to delete the bin folder, check to run the checkstyle and run2, run3, run4 as described above. You can specify command line arguments like this:

> ant run4 -Dargs="4 12 26 10"

You do not need to include the file biuoop.jar, and can assume it is available in the same directory as build.xml.

**Make sure you submit the assignment according to the submission instructions. ** **Run the task on the university's servers (for example, with Mobox) and on the CMD and make sure that it runs with the runing command outside your workspace with the folder you're actually submit. **

Questions and answers from the forum(s)

  • Can I change the signature of Ball.moveOneStep() method? (I need to give it the boarders to bounce of)
    • No, it's up to you how to implement it exactly, but make sure that in your final code, the methods have the exact signatures given in the assignment.
  • In the BouncingBallAnimation.drawAnimation() can I set up the GUI surface / sleepFor to be a different size from the one in the example?
    • You should keep the sizes of the GUI surface and sleepFor the same as in the example.

Several End Notes

  • Open your mind - in this assignment (and other to come), we provide you with some classes and methods which are obligatory in your implementation; but it is very likely that you need to implement other classes and methods to make the job right. Good design is a key to your success in the course assignments.
  • You are welcome to search the web for technical issues, mathematical or programming questions, and pretty much everything. Use it. Google would be your mentor for all your professional life. (The only think you can't do is copy code from published solutions, but you can re-write same ideas in your own code).
  • As (almost) all the following assignments will be built on top of this one (especially the Line and Ball classes), it is important you test them as much as you can. You'll get feedback on the assignment, but a 100 score does not guarantee that you don't have bugs, which you might only be aware of during the following assignments.
  • You are not allowed to use the java.awt.geom.Line2D class.
  • Think which cases can be problematic in your code and how you deal with them

Good Luck!