ScriptHighlighter

Saturday, February 28, 2015

Windows 8 Game Development using C#, XNA and MonoGame 3.0: Building a Shooter Game Walkthrough – Part 8: Here comes the Boom!

In part seven of this series we expanded our game by adding a laser gun to the player’s ship and code that detects collisions between a laser beam and an enemy mine.  When a laser beam collides with an enemy mine the enemy is removed from the list of “active” mines.  Effectively, the enemy is destroyed.  Pretty cool eh?  But, wouldn’t it be cooler and more satisfying if the enemy mine was destroyed in a burst of flames, their remains scattered to the winds?  That is exactly the effect we will be adding in this step.

First let’s “true up” our project.  You can download the code base from which I will be working here. This project should contain all the features of Tara Walker’s tutorial series and also my contribution from part seven.

Step 1 – Create the Explosion Class

The first thing we need to do is add a new class to our game project.  Let’s call this class Explosion.cs.  The explosions class is not much different than our player, enemy, or laser classes.  This class has many of the save variables and methods as the classes mentioned above.
At the top of our new class we Ithe following namespace references.

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using ShooterTutorial;

Just like we did in previous steps we are going to add the following stub methods to our class, Initialize(), Update(), and Draw().
public void Initialize()
{
}
public void Update(GameTime gameTime)
{
}
public void Draw(SpriteBatch spriteBatch)
{
}

Next we will define a series of variables that will render our sprite animation, track the location of the explosion, return the height and width of the explosion sprite, and finally, track the explosion's time to live.  This is the amount of time that we will render the explosion animation.  Explosions can’t go on forever (as much as we may wish they would).  All good things must come to an end.
Animation explosionAnimation;
Vector2 Position;
public bool Active;
int timeToLive;
public int Width
{
    get { return explosionAnimation.FrameWidth; }
}
public int Height
{
    get { return explosionAnimation.FrameWidth; }
}

Let’s modify the Initialize() method to accept an instance of our Animation class and a Vector2 called position.  The position will be that of the exploding enemy mine.  The animation class will be responsible for looping through each frame of our sprite strip and displaying the a single image from a series.

public void Initialize(Animation animation, Vector2 position)
{
    explosionAnimation = animation;
    Position = position;
    Active = true;
    timeToLive = 30;
}

The next step is to modify the Update() method to call our animation class’ update method, decrement the time to live and set the explosion’s active flag to false once it’s time to live has expired.

public void Update(GameTime gameTime)
{
    explosionAnimation.Update(gameTime);

    timeToLive -= 1;

    if (timeToLive <= 0)
    {
        this.Active = false;
    }
}

The final modification to the explosion class is in the Draw() method.  Here we invoke our animation class’ draw method to send the sprite frame to the buffer for rendering.

public void Draw(SpriteBatch spriteBatch
{
    explosionAnimation.Draw(spriteBatch);
}

Step 2 - Wiring the Explosion Class into the Main Game Class

For this tutorial I decided that it may be possible to have more than one “active” explosion being rendered at one time. Therefore I am going to need a collection to hold any possible explosions that are touched off.   Add the following lines of code to the top of the Game1.cs class.

// Collections of explosions
List<Explosion> explosions;

//Texture to hold explosion animation.
Texture2D explosionTexture;

The first line of code establishes a list of explosions.  The second line defines a Texture2D structure that will hold our sprite strip.
Now is a good time to add the explosion sprite strip to our content builder project.  To do this, first navigate to the location of the explosion.png graphics file.  If you open the contents of this files using a graphics editor such as Paint.NET you will see that this is a long rectangular “strip” image containing eleven sprites of the explosion in various states.  Our animation class loops across this strip displaying each image briefly to provide the illusion of continuous animation.  This works exactly the same way a cartoonist would draw and photograph a series of images and then display them in rapid succession to produce an animated feature.
Next we will add a single line of code to the Initialize() method. This will instantiate our list of explosions.

// init our collection of explosions.
explosions = new List<Explosion>();

Now let’s load our sprite strip into the Texture2D struction defined earlier.  Add this line of code to the LoadContent() method of the Game1.cs class.

// load the explosion sheet
explosionTexture = Content.Load<Texture2D>("Graphics\\explosion");

There is one last bit of setup we need to do before we can get to the fun stuff (blowing up enemies).  Let’s create a helper method that will initialize and insert a new instance of an explosion into our explosions collection.  Add this method to the bottom of the Game1.cs class.

protected void AddExplosion(Vector2 enemyPosition)
{
    Animation explosionAnimation = new Animation();

    explosionAnimation.Initialize(explosionTexture,
        enemyPosition,
        134,
        134,
        12,
        30,
        Color.White,
        1.0f,
        true);

    Explosion explosion = new Explosion();
    explosion.Initilize(explosionAnimation, enemyPosition);

    explosions.Add(explosion);
}

This method is pretty simple.  First we create a new instance of the animation class using the explosion sprite strip.  Next we create a new instance of an explosion and pass in the explosion animation and the last position of the enemy ship that will be exploding.  Lastly, this explosion instance is added to the list of “active” explosions.
Now the fun begins!   We already have code that detects collisions between the enemies and the player and also between the enemies and laser beams.  Let’s inject code at those locations to add an explosion.
Find the DetectCollisions() method. Inside that method you will find a loop for each laser beam that has been fired and is still active.  Within that loop is a bounds check between the rectangle of the laser beam and that of an enemy mine.  Let’s add our explosion code inside of that bounds check.

// test the bounds of the laser and enemy
if (laserRectangle.Intersects(enemyRectangle))
{
    // Show the explosion where the enemy was...
    AddExplosion(enemies[i].Position);
    // kill off the enemy
    enemies[i].Health = 0;

    // kill off the laserbeam
    laserBeams[l].Active = false;
}

Add the same line of code inside the bounds check for the player’s ship and the an enemy.

if (playerRectangle.Intersects(enemyRectangle))
{
    // kill off the enemy
    enemies[i].Health = 0;
    // Show the explosion where the enemy was...
    AddExplosion(enemies[i].Position);
    // deal damge to the player
    _player.Health -= enemies[i].Damage;

    // if the player has no health destroy it.
    if (_player.Health <= 0)
    {
       _player.Active = false;

    }
}

The last two steps for adding the explosion animation to our game is to add the Draw() and Update() methods for our explosions.
Add this code to the Draw() method of the Game1.cs class.

// draw explosions
foreach(var e in explosions)
{
    e.Draw(_spriteBatch);
}

This code simply loops across the explosion list and calls the Draw() method of each explosion class it contains.
Next we call the update method of our explosion class(es).  This advances the displayed animation from based on the game time.  This code is very similar to the draw code we added above.  Let’s extract this loop into it’s own method.

private void UpdateExplosions(GameTime gameTime)
{
    for (var e = 0; e < explosions.Count; e++ )
    {
        explosions[e].Update(gameTime);

        if (!explosions[e].Active)
        explosions.Remove(explosions[e]);
    }
 }

This code loops across the explosions collection and checks to see if the explosion is still active.  If the explosion is no longer active (it has played its entire animation) then it is removed from the explosions list.  Let’s add our new method inside the Update() method of the Game1.cs class.

UpdateExplosions(gameTime);

Conclusion


In this tutorial we didn’t really do anything differently than was has already been demonstrated in previous steps.  You may begin to see a pattern emerging in these game classes. They all contain an Initialize(), Update(), and Draw() methods.  These are the bacis functions that any game object must perform.  It must be created, it must react to user input, AI, or the world around it, and it must be rendered to the game screen.
In the next tutorial we will add sound effects and game music.  It’s really simple to do and adds a new level of polish and immersion to your game project.