In this program assignment, you will implement classes for a very minimalist version of the classic video game called Asteroids. While the requirements for this assignment are very basic, you also have the freedom to adapt or expand on the basic ideas presented here in many ways if you would like to customize the game.
Note: For simplicity, we will not be implementing the full physics of the original Asteroids game. Instead, we will use a simplified physics approach that is much simpler to program. If you're interested in comparing your result here to the original, there are several playable versions of Asteroids available on-line, including this one.
In the variant of Asteroids you will implement, there are only three kinds of objects: your ship, the bullets your ship fires, and the asteroids. All of these objects move in straight lines, although you can steer your ship and control its speed.
Your task is to write the four main classes: Ship
, Bullet
, Asteroid
, and Space
. You may write additional classes to structure your solution if you desire. Hint: consider consolidating common features of classes into one or more superclasses of your own design.
Unlike earlier assignments, here we will use a world with a cell size of 1 pixel by 1 pixel. In Greenfoot, actors by default have a size determined by their image, so the actors in this program will be much larger than a single cell. Actor locations--that is, cell coordinates--will be in pixel sizes here. Actors are drawn so that their image is centered on their location. Also, the getIntersectingObjects()
method takes into account the Actor's physical size, not just its location, so it works as you would expect for actors that are larger than a single cell in size.
The Space
class represents the world for your game. It must provide two constructors: a constructor that takes a width and a height, and a default constructor. Both constructors should ensure that the world is created with a cell size of 1 pixel square. For the default constructor, you pick your own default world size--you might start with a size like 500x500 pixels, and then adjust the size larger or smaller so that it looks good on your screen.
For the Space
image, you can use the backgrounds/space1.jpg
image provided in Greenfoot's image library, or you can import another image from a file to customize the look of your game (use the "Import from file..." button when setting the image, and provide a PNG, JPG, or GIF image that you have found on the web or created yourself--even a photo will work).
Finally, your Space
class should provide a method called populate()
method that creates one ship in the center of the world facing north, and creates 5 randomly placed asteroids, each of which has a random speed between 1-5, and a random orientation from 0-359. Write your default constructor so that it calls populate()
to set up the world in a ready-to-play configuration.
The Asteroid
class represents the "hazard" in your game. It is simply a rock floating through space. This class must provide a constructor that takes two integer parameters: a speed (in pixels per turn), and a rotation (in degrees).
The Asteroid
class should provide a method called getSpeed()
that returns the asteroid's speed. Note that the Actor
class already provides a getter and setter for the object's rotation.
For the Asteroid
image, you can download and import the image below, or you can import another image from a file to customize the look of your game:
The behavior of an Asteroid
is simple: it moves ahead on each call to act()
the distance specified by its first constructor parameter (its speed). Remember that the Actor
class provides a move(int)
method that moves a specified distance forward in the direction the actor is currently facing.
There is one extra twist to moving an asteroid--if, after moving the asteroid forward, it is located on any edge of the world, it should "wrap around" to the other side. In other words, if after moving, the asteroid ends up on the northern edge of space, it should be transported to the corresponding spot on the southern edge, as if it flew off the top edge and re-entered the world on the bottom edge. Implement the same processing for the left/right edges of the world as well.
Finally, if the asteroid collides with a ship or bullet, both the asteroid and the ship should be removed from the world (but asteroids harmlessly pass through each other :-)).
The Bullet
class represents the shots your ship fires at the asteroids. It is simply a projectile flying through space. This class must provide a constructor that takes two integer parameters: a speed (in pixels per turn), and a rotation (in degrees).
The Bullet
class should provide a method called getSpeed()
that returns the bullet's speed. Note that the Actor
class already provides a getter and setter for the object's rotation.
For the Bullet
image, you can download and import the image below, or you can import another image from a file to customize the look of your game:
<-- It's a really small red streak right there!
The behavior of a Bullet
is simple: it moves ahead on each call to act()
the distance specified by its first constructor parameter (its speed). When a bullet reaches the edge of the world, it is removed from the world--bullets do not "wrap around" like asteroids do. Also, if the bullet collides with an asteroid, both should be removed from the world.
The Ship
class represents your ship in space. Unlike the other objects, it is steerable using an on-screen thumbstick (on an Android device) or the keyboard (on a PC). Like the other objects, it has both a speed and a rotation. It must provide a getSpeed()
method to get its current speed, but can use the existing getter and setter for rotation that it inherits from the Actor
class.
The Ship
class must provide a default constructor: a ship always starts with a speed of zero, facing directly north (a rotation of -90 degrees).
Movement of the ship is just like for asteroids, with "wrap around" at the borders of the world.
Unlike the other actors, however, the ship is controlled by your actions. The thumbstick, or directional pad (D-pad), allows you to use your finger to touch on the north, south, east, or west sides of a thumb control on-screen. On your PC's keyboard, you can use the arrow keys, or the W/A/S/D keys, which Greenfoot4Sofia treats the same way as the on-screen D-pad on an Android device.
Implement the following methods in your Ship
class to respond to D-pad actions:
public void dpadNorthIsDown()
public void dpadEastIsDown()
public void dpadSouthIsDown()
public void dpadWestIsDown()
Implement your ship so that it turns (rotates) 5 degrees left or right if the west or east side of the D-pad is down. Your ship should also speed up by 1 (accelerate) if the north side is pressed, or slow down by 1 (decelerate) if the south side is pressed. Be sure not to allow your ship's speed to become negative.
Finally, to shoot, your ship must create a new Bullet
. For simplicity, create the bullet at the same location as the ship, with the same rotation as the ship, and a speed of 10. Do this if the user taps/touches the screen (or, on a PC, clicks the mouse). Screen touches cause the following method to be invoked (if it exists):
public void onScreenTouchDown()
For the Ship
image, you can download and import the image below, or you can import another image from a file to customize the look of your game:
All program assignments are submitted to Web-CAT. Use the Controls->Submit... menu command to submit your work.
After you complete the requirements described above and are happy with your Web-CAT submission, you may wish to add other features to your solution. There are many ways you can do this. Here are some possibilities you might want to think about:
You may notice that using integer coordinates (and distances and speeds) in your program produces a slightly "jerky" movement pattern for your ship. Greenfoot4Sofia allows you to use floating point coordinates and distances for actors. If you change your ship to use full floating point behaviors everywhere, you will get smoother movement.
How would you implement the physics model of the original game, where ship orientation and velocity were independent of each other? In the original game, the ship could only accelerate, not decelerate. To slow down, you had to point the ship in the opposite direction and fire your engines to apply thrust opposite to your current direction.
In the original Asteroids
, the asteroids came in different sizes. When a bullet hit a larger asteroid, it "broke apart" into smaller pieces that flew in random directions with random speeds. You might try adding three sizes of asteroids. You can even limit larger asteroids to lower speeds, allowing smaller ones to take on higher speeds.
It is possible to add a new type of object that represents an explosion, and "create" one when a bullet collides with an asteroid (or an asteroid collides with the ship), having it remove itself from the world after a certain number of turns.
Consider how you would keep score, and how you would indicate the score to the player.
Video games often do not allow "unlimited" firing speed for the player, and instead impose a "reload" time. Think about how you might add such a restriction to the bullet firing of the ship.
How would you add a UFO that shoots back at the ship?
There are many possible visible enhancements as well to make the game more interesting or attractive.
What other modifications can you think of?