Lab 12 - Inheritance

Instructions

Follow each step carefully. There is no autograder for this assignment, and you'll soon understand why. When you're done, call over your lab TAs, who will grade you on the spot. If you leave lab without being graded, you will receive a 0. Do not ask to be regraded!

What You Cannot Use

You may not use anything beyond Chapter 4.5. This includes but is not limited to:

Any violation results in a score of 0 on the lab.

Please contact a staff member if you are unsure as to whether you're allowed to use something.

Problems

In this lab you will be working on finishing a breakout/brick breaker/Arkanoid clone. If you have never heard of this game before, please go to https://www.coolmathgames.com/0-brick-breaker and play it for a few minutes to get an idea of how the game works. (Note that in this version, the paddle is controlled by the mouse.)

You won't be implementing the entire game, e.g., the graphics or collision detection. Instead, your job is to design a few classes that handle the object hierarchy in the system.

Download the starter code from Canvas and import it into IntelliJ. Nothing will compile for the time being, because several classes (that you will write) are missing.

GameObject Class

First, design the abstract GameObject class, whose constructor receives four double values: x, y, width, and height. Store these as instance variables and write the relevant accessor and mutator methods. This class represents an entity in the game.

Also, make GameObject implement the ICollidable interface, which describes objects that can collide into one another. Hopefully, you understand why we might want that functionality. An object that responds to collisions with others must override the handleCollisions method. In a future step, we'll see how it works. Finally, GameObject should declare the following abstract methods:

Paddle Class

Next, go into the Paddle class and make it extend GameObject. This will require you to design a constructor that then calls the superclass constructor. The Paddle constructor, however, should only receive two values: the starting x and y coordinates. For its dimensions, initialize two private, static, and final integers to denote the width and height of the paddle to be 100 by 20 pixels, then pass these values to the superclass constructor. The Paddle class should also store two new fields: velX and velY representing the \(x\) velocity and \(y\) velocity respectively. When you press the left and right arrow keys, the paddle will move to the left and to the right (this behavior is already implemented into the system). Because GameObject implements ICollidable, the Paddle class will inherit the necessary methods for collision handling. This will require you to override three methods: isPaddle, isBall, and isBrick. Use common sense to correctly implement these methods.

Hint: Seriously, just use common sense! If the class is Paddle, what should isPaddle return? What about the other two methods?

Ball Class

Move into the Ball class. You will see that it is almost finished. Change the constructor to initialize the velocity variables to be random double values between -10 and 10 (inclusive or exclusive - doesn't matter) rather than the existing values.

Then, take a look at the update method. While there is nothing here that we want you to change or add to, take a few minutes to discuss with your partner(s) about the code and how it works.

Warning: Every semester, we see a number of students who, for whatever reason, do not do this step correctly and just arbitrarily pick a number. We don't mean "you pick the number," we mean that you should use Math.random() or the Random class to generate the random values.

Then, look at the handleCollisions method. Inside, we loop through all the entities in the system and check to see if the current ball collides with any of them. If there is a collision with an object, we check to see if that object is either a paddle or a brick. In the former case, we perform some simple vector math to update the ball's velocity. In the latter case, we remove the brick from the list of entities and reverse the y velocity of the ball. Again, take some time to look through this code and discuss it with your partners.

Brick Class

Lastly, finish designing the Brick class, which should also extend GameObject. This should be extremely straightforward. Identical to Paddle, its constructor should receive only positional values, but you need to pass to the superclass constructor the dimensions. The brick dimensions should be 50 by 20 pixels.

Final Thoughts

After implementing all of the classes, the project should compile without errors. Go into BreakoutRunner and run the program from the main method. Move the paddle around with the left and right arrow keys.

This is a very small lab, but hopefully you now understand the purpose of abstract classes: they serve as models for classes that other classes should extend. Abstract classes, of course, cannot be themselves instantiated, because it is nonsensical to do so. If you wish, you can delve deeper into the details of Java Swing and the other classes used in this lab.

Zip your lab and submit it to Canvas. Let your graders know, then you may leave.