Creating a Flash platform game with Flixel and Flex – Enemies

Demo

To give the player something to do we will add some enemies. These enemies will be quite dumb, simply moving left and right across the top of the blocks we have added. Even though this is not particularly advanced behaviour, it was fairly common with a lot of old 8/16 bit platform games.

First up we define a constant that controls how many enemies will be added to the level in the GameState class.

protected static const ENEMY_COUNT:uint = 10;

Then we add a FlxArray to hold the new enemies.

protected var enemies:FlxArray = new FlxArray();

We then make a call to the new function addEnemies in the constructor (after we have added the blocks to the level).

public function GameState()
{
 // ...

 for (var j:uint = 0; j < NUMBER_RANDOM_BLOCKS; ++j)
  addRandomBlocks();

 addEnemies();

 // ...
}

The addEnemies function will place the enemies on top of the blocks randomly throughout the level. However, we can’t place an enemy on top of any block, because there is a good chance that two blocks have been placed in top of each other, meaning there is no room for our enemy.

protected function addEnemies():void
{
 var enemyCount:uint = 0;

 for each (var block1:FlxBlock in this.levelBlocks)
 {
  var enemyStartX:Number = block1.x;
  var enemyStartY:Number = block1.y;
  var collides:Boolean = false;

  for each (var block2:FlxBlock in this.levelBlocks)
  {
   var xCollision:int = enemyStartX + (BLOCK_DIMENSIONS>>1);
   var xCollision2:int = xCollision + BLOCK_DIMENSIONS;
   var yCollision:int = enemyStartY - (BLOCK_DIMENSIONS>>1);
   var yCollision2:int = yCollision - BLOCK_DIMENSIONS;

   if (block1 !== block2 &&
    (block2.overlapsPoint(xCollision, yCollision) ||
    block2.overlapsPoint(xCollision, yCollision2) ||
    block2.overlapsPoint(xCollision2, yCollision) ||
    block2.overlapsPoint(xCollision2, yCollision2)))
   {
    collides = true;
    break;
   }
  }

To check this we loop through the level blocks twice. This way we can test each block for a collision in the space above it with every other block in the level. We need to find a block where a 2×2 block area (so 16×16 pixels) above the top left corner is free (this is because our enemies take up the space of 4 blocks).

To test this we need to test 4 points in space. The first will be half a block up, and half a block across. This effectively tests the area highlighted in red below.

If you are not familiar with it, the >> operator is called a bit shift. The actual details of this operator are not important; all you need to know is that by calling >>1 on an int you are effectively halving its value. It is more efficient that calling BLOCK_DIMENSIONS/2, and you get to impress all your friends with an obscure operation.

We then test the area of the next block up.

Then we repeat the process one block to the right.

In the example above, the block at the bottom of the image would not be suitable for an enemy placement because there is a collision with the second test. This sets the collision flag to true, which means we do not add an enemy here.

  if (!collides && enemyStartX > 0 && enemyStartY > 0)
  {
   enemies.add(this.add(new Enemy(enemyStartX, enemyStartY, block1.width)));
   ++enemyCount;
  }

  if (enemyCount >= ENEMY_COUNT)
   break;
 }
}

If the space above the block was clear we then create a new Enemy, which is added both to the GameState and to the enemies collection. We increment the enemyCount counter, and then either place the next enemy, or if they have all been placed break out of the loop.

public override function update():void
{
 super.update();
 FlxG.collideArray(levelBlocks, player);
 FlxG.collideArrays(playerBullets, levelBlocks);
 FlxG.collideArrays(enemies, levelBlocks);
 FlxG.overlapArrays(playerBullets,enemies,bulletHitEnemy);
}

The enemies will collide with the level blocks, and with the players bullets. In the update function we test for these collisions. For the bullet / enemy collision, we set the bulletHitEnemy function to be called in the event of a collision.

private function bulletHitEnemy(Bullet:FlxSprite,Bot:FlxSprite):void
{
 Bullet.hurt(0);
 Bot.hurt(1);
}

In the bulletHitEnemy function we call the hurt function on both the bullet and the enemy. This will remove the bullet from the level, and cause the enemy to suffer some damage. If the enemy suffers enough damage it will then be killed.

Next we need to create the Enemy class.

package
{
 import org.flixel.*;

 public class Enemy extends FlxSprite
 {
  [Embed(source="../media/enemy.png")]
  protected var EnemyImage:Class;

  [Embed(source="../media/enemygibs.png")]
  protected var EnemyGibsImage:Class;

  protected static const ENEMY_SPEED:Number = 20;
  protected static const ENEMY_HEALTH:int = 2;

To start with we embed some images, one for the enemy itself, and one for the gibs that will fly when the enemy is killed. We also specify some constants the define the enemy’s health and speed.

  protected var startingX:int;
  protected var maxHorizontalMovement:int;
  protected var gibs:FlxEmitter;

The startingX variable stores the starting position of the enemy. Since all enemies start at the left of a block, and we know how wide a block is, we can use starting with the enemies current position to determine when it should move back to the right to avoid falling off the edge.

The maxHorizontalMovement variable is the width of the underlying block. This, in combination with the startingX variable, stops the enemies moving off the edge of the block.

The gibs variable will hold a FlxEmitter, which is like a particle system, which will be display an explosion of gibs when the enemy is destroyed.

  public function Enemy(X:int, Y:int, maxHorizontalMovement:int)
  {
   super(EnemyImage, X, Y, true);

   this.y -= this.height;
   this.startingX = X;
   this.maxHorizontalMovement = maxHorizontalMovement - this.width;
   this.velocity.x = ENEMY_SPEED;
   this.health = ENEMY_HEALTH;
   this.gibs = FlxG.state.add(new FlxEmitter(0,0,0,0,null,-1.5,-150,150,-200,
      0,-720,720,400,0,EnemyGibsImage,20,true)) as FlxEmitter;

   addAnimation("anim", [0, 1], 12);
   this.play("anim");
  }

All of this code is straight forward. We simply setup the underlying FlxSprite variables along with those we specified ourselves, and then setup the enemy’s animation. We also create a new FlxEmitter, which will display the shower of gibs when the enemy dies.

  public override function update():void
  {
   super.update();

   if (this.x - this.startingX >= maxHorizontalMovement)
   {
    this.x = this.startingX + maxHorizontalMovement;
    this.velocity.x = -ENEMY_SPEED;
   }
   else if (this.x - this.startingX <= 0)
   {
    this.x = this.startingX;
    this.velocity.x = ENEMY_SPEED;
   }
  }

In the update function we change the velocity of the enemy if it has moved over the edge of the underlying block.

  public override function hitWall(Contact:FlxCore=null):Boolean
  {
   this.velocity.x = -this.velocity.x;
   return true;
  }

The hitWall function will be called if the enemy has hit a wall. Since we know the path is clear over the left of the underlying block, this means that the enemy hit a block as it moved right. In this case we simply set the velocity to move the enemy back to the left.

  public override function kill():void
  {
   super.kill();

   this.gibs.x = this.x + (this.width>>1);
   this.gibs.y = this.y + (this.height>>1);
   this.gibs.restart();
  }

 }
}

The kill function is called once the enemy’s health has dropped to 0. Managing the health value is all taken care of by the underlying FlxSprite class. Calling the FlxSprite kill function will remove the enemy from the level. We then position the FlxEmitter referenced by the gibs variable to the enemy’s last position, and call restart to play the effect.

Popularity: 1% [?]

Related posts:

  1. First demo of Flixel on Android Demo The last article showed you how to get a...
  2. Creating a game on Google Android game with Flixel – Getting Started The iPhone has taken the world by storm, but with...
  3. Методи Методи: 1 за да декларираме методи , трябва да го...
  4. Java jar примери Структура на проект Ето пример за структора на проект, ще...

Related posts brought to you by Yet Another Related Posts Plugin.

You can leave a response, or trackback from your own site.

Leave a Reply

Задвижван с помощта на WordPress | Compare Cell Phone Plans at iCellPhonePlans.com | Thanks to Cheap Palm Pixi, Bromoney and Wordpress Themes