Benefits of Polymorphism
Let’s make an expansion to the Asteroids Game that we built for PA4. Let’s add some new feature(s) that we like, and we’ll see how some parts of the design facilitate this, and possibly how some design choices make it more difficult.
Standing on the Shoulders of Giants
You’ve already done great work to complete PA4. For this lab, make a new Java Project in Eclipse, and begin by:
- downloading and reviewing 📄 the professors' reference solution (slightly updated here compared with earlier in the semester) and use this code for this lab or
- copying your own .java files from PA4 into the Java Project for this lab
⏲️ Take a minute
Take a minute and review the code to remind yourself about how things worked. The UML Diagram from P4 should still be mostly valid. **In general, you should be creating a new subclass of the things you want to change, and not modify existing code except AsteroidsGame slightly to invoke your new class’s constructor.Choose your own Adventure
What you think would be most interesting to modify about this game will likely differ from others. That’s fun! …and difficult to write an autograder for. You will not submit to gradescope for this lab, but will submit to Canvas if your instructor requires it. We have imagined a few things you might enjoy considering as the starting point for your own expansion. You are welcome, but not required to use any of these:
New Feature: Color Changing…
There’s a lot of fun to be had with changing some colors around.
- To change colors, you’ll need to change the
StdDraw
pen color before drawing each element, and - if you don’t want a change of color in drawing one instance of one object to persist for otherDrawable
s - set it back (to white) after drawing each element. - To cycle between different colors, consider adding a
counter
that gets incremented with eachdraw
similar to how it works withBullet
and itsupdate
method. Then, use the value of the counter to determine when to change color and/or which color to use.- if the cycle will be between more than 2 colors, it might be best to put the colors in an array, and use the counter as an index into the array (mod
%
being your friend here).
- if the cycle will be between more than 2 colors, it might be best to put the colors in an array, and use the counter as an index into the array (mod
Twinkling Stars
Perhaps with some random frequency, it would be neat if the stars “twinkled”…
Implementation Hints
Begin from a ton of existing code as described in Standing on the Shoulders of Giants above...
- Create a new class that extends Star. (I called mine TwinklingStar.)
- Override draw and every so often, either don't super.draw or change the pen color before and after you do.
New Feature: Flashy Saucers
Saucers are scary! 😱 But they don’t look it. What if they flashed red?
Implementation Hints
Begin from a ton of existing code as described in Standing on the Shoulders of Giants above...
- Create a new class that extends Saucer. (I called mine FlashingSaucer.)
- Override draw and every so often, change the pen color before and after you invoke super.draw.
New Feature: Rainbow Bullets
It’s dangerous to go alone, take this! 🌈 The bullets are the only defense the player has, they’re already fabulous, they should look it.
Implementation Hints
Begin from a ton of existing code as described in Standing on the Shoulders of Giants above...
- Create a new class that extends Bullet. (I called mine RainbowBullet.)
- Add an instance variable that is an array of Color objects
- Override draw and every so often, change the pen color before and after you invoke super.draw.
New Feature: Rainbow Ship
This puny little vessel is the only thing standing between the player and certain doom of the cold void of space. It’s basically a superhero space unicorn 🦄, it should look like one.
Implementation Hints
Begin from a ton of existing code as described in Standing on the Shoulders of Giants above...
- Create a new class that extends Ship. (I called mine RainbowShip.)
- Add an instance variable that's an array of Color objects
- Override draw and every so often, change the pen color before and after you invoke super.draw to the next color in the array.
New Feature: Face-steroids
At this point in the semester you may be interested in blowing 💨 off some steam 😤. Consider making a specialization of the Asteroid
class that looks a little different than the circles from PA4… Feel free to find your own image file or to grab one of these (you should right click on the image and choose “save image as..”):
Implementation Suggestions
- Begin from a ton of existing code as described in Standing on the Shoulders of Giants above.
- Create a new class that extends
Asteroid
. (Call it what you like, I tend to overdo it on portmanteaus if you haven’t noticed, so mine wasFacsteroid
.) - add a String field to the new class to hold the filename of the image you want to use.
- add 2 double fields to hold the scaled width and height of the image.
- implement the required constructor to invoke the super constructor (it will have to have the same parameter as the super constructor).
- either hardcode the image filename or add a parameter to your constructor to pass it in.
- Leverage
GameDriver.scaledWidthHeight
to compute the values required to set the scaled width and height fields.
- override the
draw()
method to draw the image (take a look at the variousStdDraw.picture
overloads). - What changes are necessary to
AsteroidsGame
?
New Feature: Homing Saucer
A Homing Saucer
could chase the Ship
rather than moving randomly.
Implementation Suggestions
- Begin from a ton of existing code as described in Standing on the Shoulders of Giants above.
- Create a new class that extends
Saucer
. (I called mineHomingSaucer
.) - Add a constructor that has a
GameElement
parameter which will be the target of the homing behavior. - Override the
newHeading
method to take advantage of theGameDriver.headingAb
rather than being random. - What changes are necessary to
AsteroidsGame
?
New Feature: Shrinking Asteroid
Rather than being destroyed by a single shot, a ShrinkingAsteroid
that was of an AsteroidSize > AsteroidSize.SMALL
could be reduced to the next smaller size (and then the smallest size would be destroyed as in the existing Asteroid
class).
Implementation Hints
Begin from a ton of existing code as described in Standing on the Shoulders of Giants above...
- Create a new class that extends Asteroid. (I called mine ShrinkingAsteroid.)
- Implement a constructor that takes the required AsteroidSize you need to invoke the superconstructor, but consider adding a field to your ShrinkingAsteroid to keep a reference to this AsteroidSize.
- Override setDestroyed. It should only do the same behavior as the super's when this ShrinkingAsteroid's size is AsteroidSize.SMALL ...
New Feature: Bomb
This is perhaps the second-most difficult of the ideas listed here. Bomb
could be a specialization of Bullet
that is launched by the Ship
when a key is pressed (I went with b) and the player can detonate with the key press (I chose the same key). When detonated, the bomb could start increasing in radius until it reaches a maximum size, and then, any Asteroid
that is within the radius of the bomb when it is detonated would be destroyed.
Implementation Hints
Begin from a ton of existing code as described in Standing on the Shoulders of Giants above...
- Create a new class that extends Bullet. (I called mine Bomb.)
- Add a field to the bomb to track whether this bomb has been detonated.
- Add a constant to the bomb to limit its duration, but make it last longer than a Bullet.
- Add a constant to the bomb to limit its explosion radius.
- Implement a constructor that takes the required Pose you need to invoke the superconstructor, and initializes the new instance variable that tracks whether it's been detonated.
- Add a getter for the new field
- Add a mutator for the new field called detonate that takes no arguments (these bombs are not possible to un-detonate, at least not the way I made them)
- Override setDestroyed. It should only do the same behavior as the super's when this Bomb is undetonated
- Override update. It should start by performing super's update, but then if it is undetonated and it is older than the bomb's max duration, update the destroyed property to true. Also, if the bomb is detonated, ignore the duration, and increment the radius, only setting destroyed to true when it's reached its maximum explosion radius
- Update the AsteroidsGame.handleKeyboardInput method to watch for whatever key you like to be pressed
- Decide how many bombs a player can have (unlimited? only 3?) and how many they can launch at the same time (only 1 allowed in game a t a time? a few? unlimited???)
- Add the necessary code to AsteroidsGame to implement your decisions.
New Feature: Asteroids Split
This is perhaps the most difficult of the ideas listed here. The idea would be that if a SplittingAsteroid
of size AsteroidSize.LARGE
was shot, it would be replaced by two SplittingAsteroid
s of size AsteroidSize.MEDIUM
. If a SplittingAsteroid
of size AsteroidSize.MEDIUM
was shot, it would be replaced by two SplittingAsteroid
s of size AsteroidSize.SMALL
. If a SplittingAsteroid
of size AsteroidSize.SMALL
was shot, it would be destroyed.
Implementation Suggestions
Because it’s during the “destroying elements” phase of the game loop (see AsteroidsGame.update
), that this feature requires the creation of new enemies, it’s difficult to avoid concurrent modification exceptions. One way to avoid this is to create a new collection to temporarily hold the new enemies and only remove them from this collection (while adding to the enemies collection) at the end of the update method (after the colliding and destroying parts are done).
Student-sourced Ideas
- Enemy of my enemy…
- occasionally “spawn” a BadBomb that after a timeout will destroy everything on screen (enemies and allies alike)
- ToughAsteroid
- Asteroid that takes multiple hits to destroy
- levels
- as the player advances through “levels”, things get harder maybe smaller asteroids or tougher, faster, etc.
- ErraticAsteroid
- changes directions