Sunday, January 25, 2015

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.

No comments:

Post a Comment