Making a Space Invaders clone with PushButton – Bullets

Google+ Pinterest LinkedIn Tumblr +

PLAY THE DEMO

DOWNLOAD THE SOURCE CODE

RETURN TO THE TUTORIAL INDEX

Up until now we have been using the XML entity and level definitions as a way or defining and creating entities i.e. every entity in the XML files is created when the level is loaded. This does not make sense for the bullets though, as they will be created in response to keyboard input. Pushbutton allows for this by giving us the ability to instantiate an entity defined in the XML files by name at runtime.

First we need to define the bullet entity. This will be done as a template. The code for the bullet template includes the same spatial, rendering and animation components as the enemy we defined in the first tutorial.

Code

A new component called DestroyIfOffScreenComponent has been created. Its purpose is to remove an entity from the game when it has moved off the screen. This is a convenient way to clean up entities that are no longer useful.

Code

In addition a new component called DamageOnContactConponent allows an entity, like a bullet, to inflict damage on another entity it collides with. The actual logic to manage the health of an entity won’t be added in this tutorial, so the DamageOnContactConponent component will simply remove the entity to which it is attached when a collision occurs.

Code

If you look closely the collisionType and collidesWithTypes properties of the Box2DSpatialComponent component were not set in the Bullet template. This is because we eventually want to have two types of bullets – those fired by the player and those fired by the enemy. To accommodate this we define a new template called PlayerBullet, based on the Bullet template. Here we define the PlayerBullet as an entity that collides with enemies.

Code

The Enemy template is modified so that it will collide with the entities based off the PlayerBullet template.

Code

The last change is to the PlayerControllerComponent, which gains a new property called bulletEntityName, which defines the name of the template from which to create the players bullets.

Code

The code for the DamageOnContactConponent component is quite simple at this point because we have not implemented the logic to actually inflict any damage. For now it listens for a collision and removes the entity to which it belongs from the game.

public class DamageOnContactConponent extends EntityComponent
{
 public var damage:int = 0;
 
 public function DamageOnContactConponent()
 {
  super();
 }
 
 protected override function onAdd():void
 {
  super.onAdd();
  
  owner.eventDispatcher.addEventListener(CollisionEvent.COLLISION_EVENT, OnCollision);
 }
 
 protected override function onRemove():void
 {
  super.onRemove();
  
  owner.eventDispatcher.removeEventListener(CollisionEvent.COLLISION_EVENT, OnCollision);
 }
 
 private function OnCollision(event:CollisionEvent):void
 {
    
  owner.destroy();   
 }

The DestroyIfOffScreenComponent component checks the position of the entity each frame and removes the entity to which it belongs from the game if it has moved off the screen.

public class DestroyIfOffScreenComponent extends TickedComponent
{
 [TypeHint(type="flash.geom.Point")]
 public var positionReference:PropertyReference;
 
 public var screenWidth:int = 480; 
 public var screenHeight:int = 384;       
 public var sideBuffer:int = 32;
 
 public function DestroyIfOffScreenComponent()
 {
  super();
 }
 
 public override function onTick(tickRate:Number):void
 {
  super.onTick(tickRate);
  
  var position:Point = owner.getProperty(positionReference);
  
  if (position == null)
   return;
  
  if (position.x > screenWidth + sideBuffer ||
   position.x < -sideBuffer ||
   position.y > screenHeight + sideBuffer ||
   position.y < -sideBuffer)
  {
   owner.destroy(); 
  }  
 }

The PlayerControllerComponent onTick function has been modified to allow it to fire the bullets. First we count down a timer called timeToNextShot that is incremented every time a bullet is fired.

public override function onTick(tickRate:Number):void
{
 // ...
 
 timeToNextShot -= tickRate;
 timeToNextShot = timeToNextShot<0?0:timeToNextShot;

If the space bar has been pressed and the timeToNextShot equals zero we reset the timeToNextShot counter and create a new instance of the PlayerBullet template. The bullets position and velocity are set so that it appears on the screen at the players position.

 if (InputManager.isKeyDown(InputKey.SPACE) && timeToNextShot == 0)
 {
  timeToNextShot = timeBetweenShots;
  
  var bullet:IEntity = TemplateManager.instance.instantiateEntity(bulletEntityName);
  if (bullet != null)
  {
   var spatial:Box2DSpatialComponent = 
    bullet.lookupComponentByType(Box2DSpatialComponent) as Box2DSpatialComponent;
    
   spatial.position = new Point(position.x, position.y);
   spatial.linearVelocity = new Point(0, -speed);
  }
 }
 
 // ...   
}

If you have read the previous tutorial series you may remember that adding animated sprites to the screen at runtime required a workaround to where the animation component was added to the entity only after the image resource was loaded (it was in the EntityFactory createExplosion function in this tutorial for those that want to take a look). This is not an issue with the method used here, because all the sprite sheets are loaded when the level is loaded, meaning the resources are ready to be used as soon as the animation components are loaded.

Share.

About Author

Leave A Reply