Chapter 13. Galactic War: Squashed by Space Rocks

We’ll make a minor enhancement to Galactic War in this chapter by adding support for an animated explosion. To facilitate this, we’ll have to write some new code to handle the timing and state properties for each sprite. The goal in this chapter is to add a handler for responding to ship-asteroid collisions. When a collision occurs, the game should animate an explosion over the ship, and then put the ship into a temporary invulnerability mode so the player can get the heck out of the way before another collision occurs.

Here are the key topics we’ll cover in this chapter:

  • Examining possible interactions among the game entities

  • Adding collision detection between the player’s ship and the asteroids

Being Civilized about Collisions

Responding to collisions in a civilized manner is the first step toward adding realistic gameplay to any game. The next step is to add a sense of timing to the response code. We’ll add explosions to show when the player gets hit by an asteroid! The new animated explosion in the game is a 16-frame sequence, which is shown in Figure 13.1.

The 16-frame animated explosion (courtesy of Reiner Prokein).

Figure 13.1. The 16-frame animated explosion (courtesy of Reiner Prokein).

When the explosion code is added to the game, the ship will literally blow up when it collides with an asteroid (see Figure 13.2).

The new animated explosion is now part of the game.

Figure 13.2. The new animated explosion is now part of the game.

Let’s take a look at the changes required to update the game to support explosions. There’s more involved here than just loading up the animation and drawing it because we have to account for timing and sprite state values. The first change is in the global section at the top of the class—note the changes in bold.

Tip

The static keyword defines a variable that does not change.

public class GalacticWar extends Applet
        implements Runnable, KeyListener {
    //global constants
    static int SCREENWIDTH = 800;
    static int SCREENHEIGHT = 600;
    static int CENTERX = SCREENWIDTH / 2;
    static int CENTERY = SCREENHEIGHT / 2;
    static int ASTEROIDS = 10;
    static int BULLETS = 10;
    static int BULLET_SPEED = 4;
    static double ACCELERATION = 0.05;

    //sprite state values
    static int STATE_NORMAL = 0;
    static int STATE_COLLIDED = 1;
    static int STATE_EXPLODING = 2;

    //the main thread becomes the game loop
    Thread gameloop;

    //double buffer objects
    BufferedImage backbuffer;
    Graphics2D g2d;

    //various toggles
    boolean showBounds = true;
    boolean collisionTesting = true;
    long collisionTimer = 0; 
    //define the game objects
    ImageEntity background;
    Sprite ship;
    Sprite[] ast = new Sprite[ASTEROIDS];
    Sprite[] bullet = new Sprite[BULLETS];
    int currentBullet = 0;
    AnimatedSprite explosion;

    //create a random number generator
    Random rand = new Random();

    //sound effects
    SoundClip shoot;
    SoundClip explode;

    //simple way to handle multiple keypresses
    boolean keyDown, keyUp, keyLeft, keyRight, keyFire;

    //frame rate counters and other timing variables
    int frameCount = 0, frameRate = 0;
    long startTime = System.currentTimeMillis();

Make the following changes near the top of the init() event method to switch the background object from an Image to an ImageEntity.

   public void init() {
       //create the back buffer for smooth graphics
       backbuffer = new BufferedImage(SCREENWIDTH, SCREENHEIGHT,
           BufferedImage.TYPE_INT_RGB);
       g2d = backbuffer.createGraphics();

       //load the background image
       background = new ImageEntity(this);
       background.load("bluespace.png");

Next, scroll down inside the init() event method a bit more until you have found the call to addKeyListener(this) and insert the following code in bold. This code loads a 16-frame explosion animation.

        //load the explosion
        explosion = new AnimatedSprite(this, g2d);
        explosion.load("explosion96x96x16.png", 4, 4, 96, 96);
        explosion.setFrameDelay(2);
        explosion.setAlive(false);

        //start the user input listener
        addKeyListener(this);

Next, go to the update() event and look for the line of code that draws the background and make the change noted in bold. Then, a few lines further down, add the new line of code shown in bold.

       //draw the background
       g2d.drawImage(background.getImage(),0,0,SCREENWIDTH-1,
SCREENHEIGHT-1,this);

       //draw the game graphics
       drawAsteroids();
       drawShip();
       drawBullets();
       drawExplosions();

Now, while you’re still in the update() method, scroll down a few lines to the part of the method that draws status information on the screen and add the following code to display the ship’s current state.

       if (ship.state()= =STATE_NORMAL)
           g2d.drawString("State: NORMAL", 5, 70);
       else if (ship.state()= =STATE_COLLIDED)
           g2d.drawString("State: COLLIDED", 5, 70);
       else if (ship.state()= =STATE_EXPLODING)
           g2d.drawString("State: EXPLODING", 5, 70);

Now, scroll down past the three draw methods and add the following method after drawAsteroids(). This is just the first version of the explosion code, and it only draws a single animated explosion. Later, the game will need to support several explosions at a time.

   public void drawExplosions() {
       //explosions don't need separate update method
       if (explosion.alive()) {
           explosion.updateAnimation();
           if (explosion.currentFrame() == explosion.totalFrames()-1) {
               explosion.setCurrentFrame(0);
               explosion.setAlive(false);
           }
           else {
               explosion.draw();
           }
       }
   }

Next, scroll down a bit more to the gameUpdate() method. Modify it with the additional lines of code shown in bold.

   private void gameUpdate() {
       checkInput(); updateShip();
       updateBullets();
       updateAsteroids();
       if (collisionTesting) {
           checkCollisions();
           handleShipCollisions();
           handleBulletCollisions();
           handleAsteroidCollisions();
       }
   }

Scroll down just past the checkCollisions() method and add the following new methods to the game. The two collision handler routines for asteroids and bullets are not implemented yet, as the goal is first to get a response for ship-asteroid collisions along with an animated explosion. The handleShipCollisions() method uses the ship sprite’s state property extensively to monitor the current state of a collision, and it adds a three-second delay after a collision has occurred so the player can get out of the way before collisions start to occur again.

   public void handleShipCollisions() {
       if (ship.state() == STATE_COLLIDED) {
           collisionTimer = System.currentTimeMillis();
           ship.setVelocity(new Point2D(0,0));
           ship.setState(STATE_EXPLODING);
           startExplosion(ship);
       }
       else if (ship.state() == STATE_EXPLODING) {
           if (collisionTimer + 3000 < System.currentTimeMillis()) {
               ship.setState(STATE_NORMAL);
           }
       }
   }
   public void startExplosion(Sprite sprite) {
       if (!explosion.alive()) {
           double x = sprite.position().X() -
               sprite.getBounds().width / 2;
           double y = sprite.position().Y() -
               sprite.getBounds().height / 2;
           explosion.setPosition(new Point2D(x, y));
           explosion.setCurrentFrame(0);
           explosion.setAlive(true);
       }
   }

   public void handleBulletCollisions() {
       for (int n = 0; n<BULLETS; n++) {
           if (bullet[n].state() == STATE_COLLIDED) {
                  //nothing to do yet
             }
         }
     }

     public void handleAsteroidCollisions() {
         for (int n = 0; n<ASTEROIDS; n++) {
             if (ast[n].state() == STATE_COLLIDED) {
                  //nothing to do yet
           }
       }
   }

What You Have Learned

This chapter tackled the difficult subject of sprite collision detection. Adding support for collision testing is not an easy undertaking, but this chapter provided you with the knowledge and explained the collision code in the core classes that make it possible. You can now draw two or more sprites on the screen and very easily determine when they have intersected or collided, and then respond to such events.

Review Questions

The following questions will help you to determine how well you have learned the subjects discussed in this chapter. The answers are provided in Appendix A, “Chapter Quiz Answers.”

1.

What is the name of the method that makes collision detection possible?

2.

How many collisions can the game detect within a single update of the game loop?

3.

What would happen if the ship were to fire a projectile that “warps” around the screen and then hits the ship? Would a collision take place? Why or why not?

4.

What should happen to the player’s ship after it has been destroyed by a collision with an asteroid? Describe a better way to “respawn” the ship than what is currently being done.

5.

What type of transform could you apply to the explosion sprite to change its size?

6.

How does the ship’s velocity affect the result of a collision when the ship is destroyed? Should the ship continue to exert momentum even while blowing up?

7.

How can the collision routine be improved upon, so that collisions are more precise?

8.

What is the name of the constant applied to the ship when a collision has taken place?

9.

What is the name of the method that updates a sprite’s animation sequence?

10.

What is the name of the method that handles the game loop for Galactic War?

On Your Own

Since we are constantly improving the game with each new chapter, there is little you can do now that will not be addressed in the next chapter. However, some improvements can be made now that are not added in future chapters. Here is one such example: Add another explosion to Galactic War so that the asteroids blow up like the player’s ship when they collide with the ship.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.15.122.235