Previous posts in this series:
In the previous part we did some collision detection between the player’s missiles and the aliens. If hit, the alien disappeared gradually (as opposed to a big explosion). Let’s add some more collision detection.
First, a small bug fix: if we keep killing aliens, eventually new one won’t be generated. The reason is the Killed event is not handled and so the number of current “live” aliens never decreases…
This is fixable by adding handling of the Killed event like so:
alien.Killed += a => {
_currentLiveAliens--;
};
Currently, the player is invincible – she cannot be killed or hurt in any way. It’s time to change that. We need to check each “live” alien with the player. If there’s a hit, we’ll create an explosion.
Where should we do the collision check? As usual in these cases, we can do that from either the aliens side or the player side. Which one is “better”? In this case I’d prefer doing it from the aliens side. Why? Because we’re already iterating over the aliens – all we need is add one additional check for collision with the single player sprite. If we’d go the other way around, we’d have to create another loop for checking against all aliens – less efficient.
First, we need access to the player component from the aliens component. we’ll do that similarly to the way we exposed the aliens component – by exposing it via a readonly field:
public readonly PlayerComponent PlayerComponent;
and setting it in the game’s constructor while creating the component:
Components.Add(PlayerComponent = new PlayerComponent(this));
The next thing we need to prepare is to expose the player’s sprite for external access (currently it’s a private field):
public Sprite Player { get { return _player; } }
Now we can actually implement the collision check in AliensComponent.Update:
var pc = AlienRaidGame.Current.PlayerComponent;
foreach(var alien in _aliens)
if(alien != null && alien.Active) {
alien.Update(gameTime);
if(!alien.IsDying && pc.Player.Active && alien.Collide(pc.Player)) {
// player hit!
alien.Hit(5); // alien hit, too!
pc.Player.Active = false; // deactivate for now
}
}
If we run the game now, any alien that hits the player causes the ship to disappear, never to appear again. Only one life right now!
Let’s add some explosion sprite when the player’s ship explodes and an explosion sound, too. We’ll use the 6 frame explosion inside the file sprites.png, which is already one of our game assets.
First, we’ll add a PlayerHit method to PlayerComponent, so that the player can handle its own hit logic:
public void PlayerHit(int power = 1) {
// player always dies
_player.Active = false;
// setup explosion
_playerExplodeSound.Play();
}
The player is simply deactivated. I’ve also added an explosion sound (in the usual way). When an alien collides with the player, this method should be called:
if(!alien.IsDying && pc.Player.Active && alien.Collide(pc.Player)) {
// player hit!
alien.Hit(5); // alien hit, too!
pc.PlayerHit();
}
This shifts the responsibility of handling hitting the player to the PlayerComponent, where it’s most appropriate.
Now for the explosion: we’ll add a Sprite field to hold it, and initialize it in a deactivated state:
_playerExplosion = new Sprite(_explosionTexture, new Rectangle(0, 153, 65, 66), 6, true, 1);
_playerExplosion.Active = false;
_playerExplosion.Origin.X = _playerExplosion.FrameWidth / 2;
_playerExplosion.AnimationInterval = TimeSpan.FromMilliseconds(400);
_explosionTexture is Texture2D object, created in LoadContent as usual. To make the explosion visible and animating, we need to add appropriate code to the Update and Draw methods (like we do with any sprite). Now we just need to activate the explosion when the player is hit:
public void PlayerHit(int power = 1) {
// player always dies
_player.Active = false;
// setup explosion
_playerExplodeSound.Play();
_playerExplosion.Position = _player.Position;
_playerExplosion.Active = true;
}
If we run now, we find out the when the player is hit, the explosion animation plays repeatedly instead of just once. We need to add this capability to the Sprite class. Add two fields to indicate whether one shot animation is enabled:
public bool OneShotAnimation;
public bool DeactivateOnAnimationOver = true;
DeactivateOnAnimationOver indicates if the sprite should automatically deactivate when the animation sequence is done (true by default). We need to update the Sprite.Update method to use these new fields:
public virtual void Update(GameTime gameTime) {
if(Active) {
if(TotalFrames > 1 && (_animElapsed += gameTime.ElapsedGameTime) > AnimationInterval) {
if(++_currentFrame == TotalFrames) {
_currentFrame = 0;
if(OneShotAnimation) {
_currentFrame = TotalFrames - 1;
if(DeactivateOnAnimationOver)
Active = false;
}
}
_animElapsed -= AnimationInterval;
}
Position += Velocity;
}
}
Now let’s initialize the explosion to use one shot animation, and voila! We have explosions. The downloadable source also includes explosion sound for the aliens (and some minor bug fixes).
Although I promised displaying stats in this part, I’ll save that for the next part.