Sunday, January 25, 2015

Anansi: Upgrades


Thinking of it, we could pick up any kinds of collectibles. We could create a different class for each bonus, but that would mean we'd have to use the instanceof operator in order to distinguish them. I think it's better to give the collectibles an internal type. This way we compare simply an enum instead of using instanceof.

We introduce the following collectibles:

  • Stroyent: increase score
  • Nuke: all enemies explode
  • Shield: gives the player temporary invicibility
  • Ammo: upgrades the bullet level
  • Health: increases the player's health

So let's change the Stroyent class to a Bonus class which can have various types.

public class Bonus extends SpriteBase {

 public enum Type {
  STROYENT,
  NUKE,
  HEALTH,
  AMMO,
  SHIELD
 }
 
 private Type type;
 
 public Bonus(Type type, Pane layer, Image image, double x, double y, double r, double dx, double dy, double dr, double health, double damage) {
  super(layer, image, x, y, r, dx, dy, dr, health, damage);
  this.type = type;
 }
 
 public Type getType() {
  return type;
 }

 @Override
 public void checkRemovability() {

  if( Double.compare( getY(), Settings.SCENE_HEIGHT) > 0) {
   setRemovable(true);
  }

  
 }
}

We load the images for the various bonuses.
Image bonusStroyentImage;
Image bonusNukeImage;
Image bonusHealthImage;
Image bonusShieldImage;
Image bonusAmmoImage;

// bonuses
bonusStroyentImage= new Image( getClass().getResource( "assets/bonus/stroyent.png").toExternalForm());
bonusNukeImage= new Image( getClass().getResource( "assets/bonus/nuke.png").toExternalForm());
bonusHealthImage= new Image( getClass().getResource( "assets/bonus/health.png").toExternalForm());
bonusShieldImage= new Image( getClass().getResource( "assets/bonus/shield.png").toExternalForm());
bonusAmmoImage= new Image( getClass().getResource( "assets/bonus/ammo.png").toExternalForm());

We spawn the various bonuses depending on a randomness level in our Settings class.

public static int BONUS_RANDOMNESS = 50;

We consider the randomness in the spawnBonus class. We could vary the frequency of the different bonus types by changing the rndBonus check from single integer to an interval. For now the bonus types except stroyent show up equally distributed.
private void spawnBonus( SpriteBase sprite) {

 Bonus.Type type;
 Image image;
 
 // set the bonus type randomly
 int rndBonus = rnd.nextInt( Settings.BONUS_RANDOMNESS);
 
 // nuke
 if( rndBonus == 0) {
  type = Bonus.Type.NUKE;
  image = bonusNukeImage;
 }
 // health
 else if( rndBonus == 1) {
  type = Bonus.Type.HEALTH;
  image = bonusHealthImage;
 }
 // shield
 else if( rndBonus == 2) {
  type = Bonus.Type.SHIELD;
  image = bonusShieldImage;
 }
 // ammo
 else if( rndBonus == 3) {
  type = Bonus.Type.AMMO;
  image = bonusAmmoImage;
 }
 // default: stroyent
 else {
  type = Bonus.Type.STROYENT;
  image = bonusStroyentImage;
 }

 
 // random speed
 double speed = rnd.nextDouble() * 1.0 + 1.0;

 // random rotation delta
 double dr = rnd.nextDouble() * 1.0 + 1.0;
 
 // random left/right rotation
 if( rnd.nextInt(2) == 0)
  dr = -dr;

 double x = sprite.getCenterX();
 double y = sprite.getCenterY();
 
 
 // create a sprite
 Bonus stroyent = new Bonus( type, playfieldLayer, image, x, y, 0, 0, speed, dr, 1, 0);
 
 // becomes visible once the ship (which is on top of the stroyent sprite) is gone
 stroyent.getView().toBack();
 
 // manage sprite
 stroyentList.add( stroyent);
 
}


With this change the collectibles look like this on the screen:



We need to deal with the various bonus items. We modify the collision check and add a method which processes the items.

/**
 * Let player ship pick up bonus items. 
 * @param bonusList
 */
private void checkBonusCollisions( List bonusList) {
 
 for( Player player: playerList) {
  for( Bonus bonus: bonusList) {
   
   // consider only alive sprites
   if( !bonus.isAlive())
    continue;

   if( player.collidesWith( bonus)) {
    
    // stop movement of sprite
    bonus.stopMovement();
    
    // collect bonus
    collectBonus( player, bonus);

    // destroy sprite, set health to 0
    bonus.kill();
    
    // remove the sprite from screen by flagging it as removable
    bonus.remove();
    
   }
  }
 }
}

private void collectBonus( Player player, Bonus bonus) {
 
 switch( bonus.getType()) {
 case STROYENT:
  // show collection score
  spawnScoreTransition( bonus, Settings.SCORE_BONUS_STROYENT);
  break;
 case NUKE:
  System.err.println( "TODO: add nuke code");
  break;
 case SHIELD:
  System.err.println( "TODO: add shield code");
  break;
 case HEALTH:
  System.err.println( "TODO: add health code");
  break;
 case AMMO:
  System.err.println( "TODO: add ammo code");
  break;
 default:
  System.err.println("Unsupported bonus type: " + bonus.getType());
 }
 
}

Now the code is similar to what it was before when we had a dedicated Stroyent bonus class, except that we can add various bonus handlers.

A note about the code which we still need to implement: In this special case I prefer to simply output an error message for the missing code. Throwing an UnsupportedOperationException or IllegalArgumentException here would be overkill. It's not really necessary and we don't want to break the game with unnecessary exceptions.

What I'm curious though is the nuke. We already have the code to let an enemy ship explode when a bullet/missile hit's it. So the nuke is just a loop over all enemies and letting them explode. Let's add this now.

The difficulty we are facing is that we can't simply run through the enemy and bonus loops again while we're already running through them. We'd get ConcurrentModificationExceptions. The solution to this is that we do the same what we already did with the bullets and missiles: We only set a flag that the nuke got fired and we fire it in the game loop. Let's get coding.

We extend the Player class:
boolean nukeCharged = false;

public void fireNuke() {
 this.nukeCharged = true;
}

public boolean isFireNuke() {
 return this.nukeCharged;
}

public void unchargeNuke() {
 this.nukeCharged = false;
}

We modify the bonus collection and explosion mechanism:
/**
 * Check if a projectile (eg player bullet/missile) hits an enemy.
 * If a collision is detected, the enemy is damaged. If enemy is killed, an explosion is spawned.
 * @param projectileList
 */
private void checkProjectileCollisions( List projectileList) {
 
 for( SpriteBase projectile: projectileList) {
  for( Enemy enemy: enemyList) {
   
   // consider only alive sprites
   if( !enemy.isAlive())
    continue;

   if( projectile.collidesWith(enemy)) {
    
    // inflict damage, reduce enemy's health
    enemy.getDamagedBy(projectile);

    // explosion animation
    if( !enemy.isAlive()) {
     
     explode( enemy);
     
    }

    // destroy sprite, set health to 0
    projectile.kill();
    
    // remove the sprite from screen by flagging it as removable
    projectile.remove();
    
   }
  }
 }
}

private void collectBonus( Player player, Bonus bonus) {
 
 switch( bonus.getType()) {
 case STROYENT:
  // show collection score
  spawnScoreTransition( bonus, Settings.SCORE_BONUS_STROYENT);
  break;
 case NUKE:
  // kill all enemies
  player.fireNuke();
  break;
 case SHIELD:
  System.err.println( "TODO: add shield code");
  break;
 case HEALTH:
  System.err.println( "TODO: add health code");
  break;
 case AMMO:
  System.err.println( "TODO: add ammo code");
  break;
 default:
  System.err.println("Unsupported bonus type: " + bonus.getType());
 }
 
}

private void nuke() {

 for (Enemy enemy : enemyList) {

  // consider only alive sprites
  if (!enemy.isAlive())
   continue;

  // set health to 0
  enemy.kill();

  // let enemy explode, spawn bonus
  explode( enemy);

 }
}

private void explode( Enemy enemy) {
 
 // stop movement of sprite
 enemy.stopMovement();
 
 // let enemy explode
 spawnExplosion( enemy);
 
 // show score
 spawnScoreTransition( enemy, Settings.SCORE_ENEMY);

 // show bonus
 spawnBonus( enemy);

}

private void checkNukeFiring() {
 for( Player player: playerList) {
  if( player.isFireNuke()) {
   
   // nuke can only be fired once
   player.unchargeNuke();
   
   // nuke all enemies
   nuke();
  }
 }
}


And we add the nuke mechanism to the game loop:
// check if player fires nuke and if so, kill all enemies
checkNukeFiring();


Looks great, works perfectly without problems when we pick up a nuke:


We'll consider the other upgrades in another blog entry.

Anansi: Collecting Items


We collect the bonus items with the player ship. Everyone likes collectibles and scoring. The more the better. We can easily add let's say another 5 score points to the player's score when the ship picks up an item.

What do we have to do with our engine? We have to

  • check if the player ship collides with a bonus item
  • add points to the player's score
  • remove the sprite
  • add a ScoreTransition to the screen

Should be easy to do and done quickly, since it's similar to code we already have. Let's get coding.

We define the score value for the picking up of bonus items in the Settings class.
public static int SCORE_BONUS_STROYENT = 5;

We check if the player sprite collides with the bonus sprites
/**
 * Let player ship pick up bonus items. 
 * @param stroyentList
 */
private void checkBonusCollisions( List stroyentList) {
 
 for( Player player: playerList) {
  for( SpriteBase target: stroyentList) {
   
   // consider only alive sprites
   if( !target.isAlive())
    continue;

   if( player.collidesWith( target)) {
    
    // stop movement of sprite
    target.stopMovement();
    
    // show score
    spawnScoreTransition( target, Settings.SCORE_BONUS_STROYENT);

    // destroy sprite, set health to 0
    target.kill();
    
    // remove the sprite from screen by flagging it as removable
    target.remove();
    
   }
  }
 }
}


And we invoke the check method in the game loop
// bonus items
checkBonusCollisions( stroyentList);

That's it. You can see how it looks like in this screenshot, check out the fading text objects with "5" around the player ship:

Anansi: Bonus


Everyone likes bonuses. In games you often get to collect bonuses (coins, etc) after you achieved something. Let's add that when we shoot down an enemy.

The game Enemy Territory: Quake Wars used something called Stroyent as collectible. So we could take a screenshot of that, create a sprite of it and let the enemy ship drop it when it gets shot down.

We have the engine to do that, so let's get coding. The code is similar to the code which we use for the enemy: Create a sprite and let it move down the screen.

The stroyent sprite floats from top to bottom:
public class Stroyent extends SpriteBase {

 public Stroyent(Pane layer, Image image, double x, double y, double r, double dx, double dy, double dr, double health, double damage) {
  super(layer, image, x, y, r, dx, dy, dr, health, damage);
 }

 @Override
 public void checkRemovability() {

  if( Double.compare( getY(), Settings.SCENE_HEIGHT) > 0) {
   setRemovable(true);
  }

  
 }
}

We create a reference to the image and the sprite and we load the image as usual.
Image stroyentImage;
...
List stroyentList = new ArrayList<>();
...
// bonus: stroyent
stroyentImage= new Image( getClass().getResource( "assets/collectibles/bonus/stroyent.png").toExternalForm());

We extend the game loop as usual.
private void createGameLoop() {
 
 // game loop
  gameLoop = new AnimationTimer() {
   
      @Override
      public void handle(long l) {
        ...
       moveSprites( stroyentList);
        ...
       updateSpritesUI(stroyentList);
        ...
       checkRemovability( stroyentList);
        ...
       removeSprites( stroyentList);
        ...
      }
  };
}

And we create a method to spawn the bonus from the exploding enemy's position.

Let's add something new: We already have a rotation mechanism, so in order to not make the floating stroyent look static we simply add a little rotation to the sprite.

We spawn the bonus item when the ship gets hit. Of course it would overlap the ship. We need to position the sprite behind the ship. We can do that with the toBack() method. This way the stroyent sprite becomes automatically visible when both the enemy ship and the explosion disappear.
private void spawnStroyent( SpriteBase sprite) {
 
 // image
 Image image = stroyentImage;
 
 // random speed
 double speed = rnd.nextDouble() * 1.0 + 1.0;

 // random rotation delta
 double dr = rnd.nextDouble() * 1.0 + 1.0;
 
 // random left/right rotation
 if( rnd.nextInt(2) == 0) {
  dr = -dr;
        }

 double x = sprite.getCenterX();
 double y = sprite.getCenterY();
 
 // create a sprite
 Stroyent stroyent = new Stroyent( playfieldLayer, image, x, y, 0, 0, speed, dr, 1, 0);
 
 // becomes visible once the ship (which is on top of the stroyent sprite) is gone
 stroyent.getView().toBack();
 
 // manage sprite
 stroyentList.add( stroyent);
 
}

All that's left is to spawn the sprite. Here's the collision check method as a whole, including the new line for the stroyent spawning:
private void checkProjectileCollisions( List projectileList) {
 
 for( SpriteBase projectile: projectileList) {
  for( Enemy enemy: enemyList) {
   
   // consider only alive sprites
   if( !enemy.isAlive())
    continue;

   if( projectile.collidesWith(enemy)) {
    
    // inflict damage, reduce enemy's health
    enemy.getDamagedBy(projectile);

    // explosion animation
    if( !enemy.isAlive()) {
     
     // stop movement of sprite
     enemy.stopMovement();
     
     // let enemy explode
     spawnExplosion( enemy);
     
     // show score
     spawnScoreTransition( enemy, Settings.SCORE_ENEMY);

     // show bonus
     spawnStroyent( enemy);
     
    }

    // destroy bullet, set health to 0
    projectile.kill();
    
    // remove the bullet from screen by flagging it as removable
    projectile.remove();
    
   }
  }
 }
}

Here's how it looks like with the bonus items.



What's left is to pick up the items.

Anansi: Scoring


I guess the FX in JavaFX stands for Effects. So let's see which ones it provides and use them.

When we hit an enemy ship, it's an achievement. We score some points. We could simply increment the high score. That would usually do it, but we'd like to pimp up our game.

JavaFX has a FadeTransition class, we should use it. Let's show the score of every enemy we shoot down on screen. We overlay the explosion with the points we score and let that text fade out slowly.

The Oracle website has a nice article about Using Text and Text Effects in JavaFX.

Looks like it can be done very easy. Let's get coding.

public class ScoreTransition {
 
 Text text;

 FadeTransition transition;
 
 public ScoreTransition( Pane layer, SpriteBase sprite, double durationMs, int score) {
  
  // create view
  text = new Text( NumberFormat.getInstance().format( score));
  
  // set visual properties
  // TODO: uses css, eg text.setStyle("-fx-font: 120px Tahoma; -fx-text-fill: white; -fx-stroke: black; -fx-stroke-width: 2;");
        text.setStroke(Color.BLACK);
        text.setStrokeWidth(0.2);
        text.setFill(Color.WHITE);
        
        // item gets visible at the center of the given sprite
  relocateToCenterOf( sprite);
  
        // make item visible on screen
  layer.getChildren().add( getView());
  
  // create fade transition
        transition = new FadeTransition( Duration.millis( durationMs));
        
        transition.setNode( getView());
        transition.setFromValue(1.0);
        transition.setToValue(0.0);
        transition.setCycleCount(1);
        transition.setAutoReverse(false);
        
        // remove object from screen
        transition.setOnFinished(new EventHandler() {

   @Override
   public void handle(ActionEvent event) {
    
    // remove from screen
    layer.getChildren().remove( getView());
    
   }
         
        });

        
 }
 
 public void play() {
  transition.play();
 }
 
 private Text getView() {
  return text;
 }
 
 /**
  * Move the view to the center of the given sprite.
  * @param sprite
  */
 private void relocateToCenterOf( SpriteBase sprite) {
  getView().relocate( sprite.getCenterX() - getView().getBoundsInParent().getWidth() / 2.0, sprite.getCenterY() - getView().getBoundsInParent().getHeight() / 2.0);
 }

}

It turned out that we can't subclass from FadeTransition. So we implement a play() method in analogy to the sprite animation class.

Each sprite we hit will give us a different score, so let's define them in the Settings class.
public static int SCORE_ENEMY = 100;

We show the score in the game with these few lines of code.
private void spawnScoreTransition( SpriteBase sprite, int score) {
 
 ScoreTransition transition = new ScoreTransition(playfieldLayer, sprite, 1000.0, score);
 transition.play();
 
}

private void checkProjectileCollisions( List projectileList) {
  ...
  if( projectile.collidesWith(enemy)) {
   ...
   // show score
   spawnScoreTransition( enemy, Settings.SCORE_ENEMY);
   ...
  }
  ...
}   
Nice and easy. You can see how it looks like in the following screenshot:


Now we have all the information we need to create a high score for the game. But let's first toy around a bit more with sprites.

Anansi: Collisions - Revisited


We already have the option to detect collsions. But there are a few things we have to consider in addition to the existing mechanism:

  • a sprite should only explode when its health is depleted
  • we only want 1 explosion per sprite
  • the exploding sprite should stop its movement

So we have to extend our checkBulletCollisions and checkMissileCollisions classes. Thinking of it, the classes are very similar - for now. I split them because maybe we'll add a mini-explosion to a detonating missile, but let's combine them until we actually add the mini-explosion.

/**
 * Check if a projectile (eg player bullet/missile) hits an enemy.
 * If a collision is detected, the enemy is damaged. If enemy is killed, an explosion is spawned.
 * @param projectileList
 */
private void checkProjectileCollisions( List projectileList) {
 
 for( SpriteBase projectile: projectileList) {
  for( Enemy enemy: enemyList) {
   
   // consider only alive sprites
   if( !enemy.isAlive())
    continue;

   if( projectile.collidesWith(enemy)) {
    
    // inflict damage, reduce enemy's health
    enemy.getDamagedBy(projectile);

    // explosion animation
    if( !enemy.isAlive()) {
     
     // stop movement of sprite
     enemy.stopMovement();
     
     // let enemy explode
     spawnExplosion( enemy);
    }

    // destroy bullet, set health to 0
    projectile.kill();
    
    // remove the bullet from screen by flagging it as removable
    projectile.remove();
    
   }
  }
 }
}

Blogspot again modifies the code. This would be the correct method signature: checkProjectileCollisions( List<? extends SpriteBase> projectileList)

The modified invocation method.
// check collisions
// ---------------------------
checkProjectileCollisions( playerBulletList);
checkProjectileCollisions( playerMissileList);

We modify the SpriteBase class with the stopMovement code
boolean canMove = true;

...

/**
 * Set flag that the sprite can't move anymore.
 */
public void stopMovement() {
 this.canMove = false;
}

...

public void move() {

 if( !canMove)
  return;
 
 x += dx;
 y += dy;
 r += dr;

} 

Now we can hit something and get animated explosions:



That looks very nice and smooth. Okay, now we're curious about the performance. Let's change the enemy spawning value and our own bullet fire rate to see how it performans with lots of explosions:


It performs quite well. This means we can wreak havoc on screen. Awesome!

Saturday, January 24, 2015

Anansi: Sprite Animation


I was wondering about the possible techniques for sprite animation in JavaFX. So I searched the web and found a very good approach. Mike's Blog has an entry about Creating a Sprite Animation with JavaFX. Looks fairly easy to do.

We have to

  • subclass from Transition
  • implement the Transition class's interpolate method which is called in every frame
  • provide a sequence of Image objects
  • use ImageView to display each Image at a given interval

The code in the blog picks the images from a single image. We have separte images for each frame in the animation, so we have to modify the code a little.

Since we'll probably need more animations, we create a base class. Just like we did with the sprites.
public class AnimationBase extends Transition {

 private final ImageView imageView;
 private final int count;

 private int lastIndex;

 private Image[] sequence;

 public AnimationBase( Image[] sequence, double durationMs) {
  
  this.imageView = new ImageView( sequence[0]);
  this.sequence = sequence;
  this.count = sequence.length;

        setCycleCount( 1);
  setCycleDuration(Duration.millis( durationMs));
  setInterpolator(Interpolator.LINEAR);
  
 }

 protected void interpolate(double k) {
  
  final int index = Math.min((int) Math.floor(k * count), count - 1);
  if (index != lastIndex) {
   imageView.setImage(sequence[index]);
   lastIndex = index;
  }
  
 }
 
 public ImageView getView() {
  return imageView;
 }

}

With this we have the base for an animation. Now to the explosion itself. We may need multiple variations of explosions, so we create a dedicated explosion class. What do we need? The explosion happens at the sprite's location, so it's convenient if we hand over the sprite to calculate the location of the explosion. Then we need to put the view of the explosion on a layer. And we'd like to remove the exploding sprite after the explosion finishes. Let's get coding.
public class Explosion extends AnimationBase {

 public Explosion(Pane layer, SpriteBase explodingSprite, Image[] sequence, double durationMs) {
  
  super(sequence, durationMs);
  
  // explosions happen at the center of the object
  relocateToCenterOf(explodingSprite);
  
  // make explosion visible on screen
  layer.getChildren().add( getView());
  
  // remove objects when animation finishes
  setOnFinished(new EventHandler() {

   @Override
   public void handle(ActionEvent event) {
    
    // flag sprite to be removable
    explodingSprite.setRemovable(true);

    // stop animation
    stop();
    
    // remove explosion from screen
    layer.getChildren().remove( getView());
    
    
   }
  });
 }

 /**
  * Move the animation to the center of the given sprite, eg an explosion is on top of the enemy ship.
  * @param sprite
  */
 public void relocateToCenterOf( SpriteBase sprite) {
  getView().relocate( sprite.getCenterX() - getView().getImage().getWidth() / 2.0, sprite.getCenterY() - getView().getImage().getHeight() / 2.0);
 }
}

This gives us options to spawn an explosion at any sprite's location with as little code as:
private void spawnExplosion( SpriteBase sprite) {
 
  Explosion animation = new Explosion( playfieldLayer, sprite, explosionSequence, 400);
  animation.play();
 
}


We load the images for the explosion sequence the usual way in our resource loading method:
Image[] explosionSequence;
...
explosionSequence = new Image[ 10];
explosionSequence[0] = new Image( getClass().getResource("assets/effects/explosion/explosion_01/explosion_w100_01.png").toExternalForm());
explosionSequence[1] = new Image( getClass().getResource("assets/effects/explosion/explosion_01/explosion_w100_02.png").toExternalForm());
explosionSequence[2] = new Image( getClass().getResource("assets/effects/explosion/explosion_01/explosion_w100_03.png").toExternalForm());
explosionSequence[3] = new Image( getClass().getResource("assets/effects/explosion/explosion_01/explosion_w100_04.png").toExternalForm());
explosionSequence[4] = new Image( getClass().getResource("assets/effects/explosion/explosion_01/explosion_w100_05.png").toExternalForm());
explosionSequence[5] = new Image( getClass().getResource("assets/effects/explosion/explosion_01/explosion_w100_06.png").toExternalForm());
explosionSequence[6] = new Image( getClass().getResource("assets/effects/explosion/explosion_01/explosion_w100_07.png").toExternalForm());
explosionSequence[7] = new Image( getClass().getResource("assets/effects/explosion/explosion_01/explosion_w100_08.png").toExternalForm());
explosionSequence[8] = new Image( getClass().getResource("assets/effects/explosion/explosion_01/explosion_w100_09.png").toExternalForm());
explosionSequence[9] = new Image( getClass().getResource("assets/effects/explosion/explosion_01/explosion_w100_10.png").toExternalForm());

Looking at the resource loading code a resource handler would come in handy. One in which we specify a folder or a file name pattern and then the array gets created automatically depending on the files. Sooner or later we'll implement that. But let's get coding, we want to see explosions.

Anansi: Collisions


Now it's time to hit something with hour bullets and missiles. There are 2 approaches for a collision detection:

  • hit zone
  • per pixel

The per pixel collision requires performance, so we choose the hit zone. It's plain and simple: We consider each sprite a rectangle and check if its bounds overlap with the bounds of another.

Checking the bounds of a rectangle is a very fast hit detection mechanism.It has a disadvantage though. We don't have a rectangle, we have an image with transparent areas. A bullet shouldn't hit the transparent area, it should hit the object. We can overcome this by not using the entire sprite as hit zone, but some areas inside of it. Examples: The missile hits only with the missile head. A Tormentor sprite is only hit at the ship's hull, but not at the legs of the ship. These aren't hard constraints that change the way the gameplay feels. In fact this is used throughout many Shoot'em'ups. Especially in bullet hell shooters where the player's ship often has only a single pixel hit zone.

Let's get coding. What we need is just another loop and a mechanism to check the overlapping of rectangles. For now it's sufficient if we use the entire sprite's rectangular area has hit zone. We'll introduce custom hit zones later.

We put this method into the SpriteBase class:
public boolean collidesWith( SpriteBase otherSprite) {
 
 return ( otherSprite.x + otherSprite.w >= x && otherSprite.y + otherSprite.h >= y && otherSprite.x <= x + w && otherSprite.y <= y + h);
 
}

Now we can easily find out if a bullet hits an enemy ship. We simply check each bullet with each enemy and perform an action if they collide. We extend the SpriteBase class with some more meaningful methods:
/**
 * Reduce health by the amount of damage that the given sprite can inflict
 * @param sprite
 */
public void getDamagedBy( SpriteBase sprite) {
 health -= sprite.getDamage();
}

/**
 * Set health to 0
 */
public void kill() {
 setHealth( 0);
}

/**
 * Set flag that the sprite can be removed from the UI.
 */
public void remove() {
 setRemovable(true);
}

And check for the collision of bullets:
private void checkBulletCollisions() {
 
 for( PlayerBullet bullet: playerBulletList) {
  for( Enemy enemy: enemyList) {
   if( bullet.collidesWith(enemy)) {
    
    // inflict damage, reduce enemy's health
    enemy.getDamagedBy(bullet);
    
    // destroy bullet, set health to 0
    bullet.kill();
    
    // remove the bullet from screen by flagging it as removable, 
    bullet.remove();
    
   }
  }
 }
}

The check for the missiles is very similar:
private void checkMissileCollisions() {
 
 for( Missile missile: playerMissileList) {
  for( Enemy enemy: enemyList) {
   if( missile.collidesWith(enemy)) {
    
    // inflict damage, reduce enemy's health
    enemy.getDamagedBy(missile);
    
    // destroy bullet, set health to 0
    missile.kill();
    
    // remove the bullet from screen by flagging it as removable, 
    missile.remove();
    
   }
  }
 }
}

Then we use the collision check methods in the game loop:
// check collisions
// ---------------------------
checkBulletCollisions();
checkMissileCollisions();

That's it. Quite easy to do. Here's a screenshot which shows that the bullets hit something and get removed. I increased the bullet counter a bit to show the effect better.