Project - Asteroids
Part 2 - The Floater superclass

Think of the different elements of this game: what is it that we're going to be needing to include on the screen?

Show/hide screen elements

Some obvious elements include:

  • our spaceship
  • asteroids
  • missiles
  • UFOs
  • score
  • number of lives left

... and of the items on that list, how many of them move or float around in space?

Show/hide moving elements

Moving elements include:

  • our spaceship
  • bullets?
  • asteroids
  • UFOs

What do these moving objects do? What will be need to keep track of for these moving elements?

Show/hide actions and attributes

Moving elements all:

  • move
  • rotate (some of them)
  • get shown, or not

Moving elements have:

  • corners (that describe their shape)
  • an x-y position in space
  • a direction that they move
  • a direction that they are pointed

Okay, now that we know what we're working with, let's do some initial set-up of our project.

Setting up the Processing project

We've already started our "AsteroidsGame" project, and that's the title of the first tab in the Processing window, the equivalent of a main method that will run our program.

To the right of that tab, click the down triangle to create New Tabs, one for each of our initial classes: Floater, Spaceship, Asteroid, and Star. We'll add additional classes/tabs later.

Let's head back over to the Floater class and take a look at how that's going to work.

2.1. The Floater class

We'll write a Floater superclass that can be extended (inherited from) by various subclasses, including the Spaceship and Asteroid classes.

abstract class Floater { protected int corners; // the number of corners, a triangular floater has 3 protected int[] xCorners; // an array list of x-coordinates of the corners protected int[] yCorners; // same for the y-coordinates protected int myColor; // a value 0-255 (grayscale) protected float myCenterX, myCenterY; //holds center coordinates protected float myXspeed, myYspeed; //holds the speeds of travel in the x and y directions protected float myPointDirection; //holds current direction the ship is pointing in degrees public Floater() { } /** * Accelerates the floater in the direction it is * pointing (myPointDirection) using kinematics */ public void accelerate (float dAmount) { // sin and cos methods use radians so we have to convert // current direction the floater is pointing to radians float dRadians = (float) (myPointDirection * (Math.PI/180)); // now change coordinates of direction of travel myXspeed += ((dAmount) * Math.cos(dRadians)); myYspeed += ((dAmount) * Math.sin(dRadians)); } /** * Turns the floater by the specified degrees */ public void turn (float degreesOfRotation) { myPointDirection += degreesOfRotation; } /** * Move the floater in the current direction of travel * as specified by values of myXspeed and myYspeed */ public void move () { myCenterX += myXspeed; myCenterY += myYspeed; //wrap around screen horizontally if (myCenterX > width) { myCenterX = 0; } else if (myCenterX < 0) { myCenterX = width; } //wrap around screen vertically if (myCenterY > height) { myCenterY = 0; } else if (myCenterY < 0) { myCenterY = height; } } /** * Draw the floater in its current position * In order to be able to draw the floater in its correct * orientation we have to use "rotate" and "translate" to * temporarily move the object into its correct spot, and * then "unrotate" and "untranslate". * See the documentation for Processing to learn more about * this process! */ public void show () { fill(myColor); stroke(myColor); //translate (x,y) center of floater to the correct position translate( (float) myCenterX, (float) myCenterY ); //convert degrees to radians for rotate() float dRadians = (float) ( myPointDirection * ( Math.PI/180 )); //rotate so the polygon will be drawn in correct direction rotate(dRadians); //draw the polygon beginShape(); for (int nI = 0; nI < corners; nI++) { vertex(xCorners[nI], yCorners[nI]); } endShape(CLOSE); //"unrotate" and "untranslate" in reverse order rotate(-1 * dRadians); translate( -1 * (float) myCenterX, -1 * (float) myCenterY ); } // Miscellaneous getters and setters public void setX(int x) { myCenterX = x; } public int getX() { return (int) myCenterX; } public void setY(int y) { myCenterY = y; } public int getY() { return (int) myCenterY; } public void setDirection(float x) { myPointDirection = x; } public float getDirection() { return myPointDirection; } public float getXspeed() { return myXspeed; } public float getYspeed() { return myYspeed; } }

There are some important details to note here. Make sure you understand each of these before moving on.

  1. The Floater class is abstract, which means that although it has "concrete" instance variables and "concrete" methods defined for it, and even has a constructor defined for it, we can't actually create a Floater object. Instead, when other classes inherit from ("extend") from Floater, they'll be able to use the methods we've defined for the class.
  2. The variables for this superclass are not public or private, they are protected. This is an access level that we haven't discussed before, a level that is somewhere between public (anybody has access) and private (nobody has direct access except for the class itself. A protected variable can be accessed directly by subclasses (which is how we'll use it here) and by other files in the same Java package.
  3. As the JavaDoc comments suggest, see the Processing documentation for further information on the "rotate" and "translate" commands and how they help to draw the Floater correctly on the screen.

2.2. The Spaceship subclass

  1. We're now in a position to be able to write the Spaceship class. In the Spaceship class (tab), write the Spaceship constructor, along with a header that indicates inheriting from the Floater. We'll create a constructor for this spaceship in a moment.
  2. Take a piece of graph paper to draw the corners of a simple spaceship shape that you can use to describe the spaceship.
  3. Show/hide how to do this

    Here is what you do.

    1. On the graph paper, identify the center of your spacecraft as 0, 0.
    2. Draw a polygonal spaceship shape around this center (pointing to the right) and identify the x-y points of your polygon. An example of one simple type of spaceship polygon is shown here.
    3. The values associated with your spaceship—the number of corners, the x-coordinates, and the y-coordinates—will be used in the AsteroidsGame.pde file to define your spaceship.
  4. Modify AsteroidsGame.pde and declare a variable of type Spaceship at the top of the file.
  5. In AsteroidsGame.pde, in the setup() method, initialize the spaceship variable by creating a new instance of a spaceship object. You don't need to supply any parameters because we'll specify them in the constructor using the protected variables of the Floater superclass.
  6. Back in the Spaceship class, let's finish off the constructor that initializes those values.
  7. Here's what I used

    class Spaceship extends Floater { /** * Constructs a new Spaceship */ Spaceship() { corners = 4; xCorners = new int[] {12, -12, -6, -12}; yCorners = new int[] {0 , 8, 0, -8}; myColor = 255; myCenterX = width / 2; myCenterY = height / 2; myXspeed = 0; myYspeed = 0; myPointDirection = 0; } }
  8. Modify AsteroidsGame.pde so that the draw() method calls the Spaceship's show() function.
  9. Try to Run the game! If it works, you should see a small screen with your spacecraft in it, pointing to the right. There are no asteroids, and your spaceship can't even move, let alone shoot, but it's a spacecraft.

    After I saw the spaceship on the screen it seemed a little too small, so I changed the pixels to make it a larger ship, but still centered on the 0,0 point.

    If you don't see your spacecraft on the screen, something didn't work, and you'll have to go back and do some debugging.

Next...

Part 3 - The Spaceship moves