Chapter 10: Adding Firepower and Creating Enemies
We have all of the basic elements to create a 2D game now: We know how to draw sprites, even animate them, and have them move around based on player input. We've also looked at how to make scrolling backgrounds to make our game more complete. But so far we've kept everything simple by having one basic entity, the player. In this chapter we'll start putting more entities into the game, first putting in fire balls the player can fire and then some enemy ships for the player to interact with. We will cover:
l How to put in simple projectiles the player can shoot
l How to put in enemies that interact with the player.
l What collision detection is and how it works in 2D.
The complete project for this chapter is ShipFighter with Enemies at xnagamemaking.com, but in our descriptions we'll be taking from the ShipFighter Animation project from last chapter.
To Shoot Fireballs
The first thing we'll do is give the player the ability to shoot fireballs. Whenever the player presses the firing key (spacebar or trigger) we'll create a fireball at the ship's location and have it travel up the screen. We'll have a separate class for the fireball objects, it will be simple and just draw them and move them up. We'll also keep a list of all the fireball objects in the game, and when the player fires it will create a new fireball and add it to the list. Here is the listing for our Fireball class:
class Fireball
{
Vector2 position;
Texture2D picture;
float speed;
public Fireball(Texture2D firePicture, Vector2 startPosition, float
updateSpeed)
{
picture = firePicture;
position = startPosition;
speed = updateSpeed;
}
public Vector2 Position{ get{ return position; } }
public void Draw(SpriteBatch batch)
{
batch.Draw(picture, position, null, Color.White, 0.0f, new Vector2(
10.0f, 10.0f ), 1.0f, SpriteEffects.None, 1.0f);
}
public void Update(GameTime gameTime)
{
position.Y -= speed *
(float)gameTime.ElapsedGameTime.TotalSeconds;
}
}
When we create a fireball we just pass in a picture of it to draw, a start position, and a speed. At each update we just move the fireball up the screen by it's current speed (moving up is subtracting from the Y in the position). And the drawing method just draws the fireball picture at it's current position.
Next we'll add a list to hold all of the fireballs that are running in a game, so in the Game1.cs add the following variable:
List<Fireball> playerFireballList = new List<Fireball>();
Remember our four steps for adding something to the Game object: declare it, initialize it, draw it and update it. The above line declares and initializes the list, next we’ll add it to the Update loop. In the Update method in the Game add the following:
for (int i = 0; i < playerFireballList.Count; i++)
{
playerFireballList[i].Update(gameTime);
if (playerFireballList[i].Position.Y < -100.0f)
playerFireballList.RemoveAt(i);
}
This addition just calls the update for every fireball and checks to see if it went off screen. If the fireball is above the screen and no longer visible we delete it. Then in the Draw loop of the game object add this:
foreach (Fireball f in playerFireballList)
f.Draw(spaceBatch);
Which just goes through every fireball in the list and draws it. We've setup a list to add fireballs too but we're not adding them in yet. What we'll do is whenever we press a fire button on the keyboard or gamepad we'll create a fireball at the current player position. But to create fireball's we'll need a texture for it, so add the file playerFireBall.png to the project. Then put a variable for the sprite in the Game object:
Texture2D playerFireballTexture;
and initialize it in the LoadContent method:
playerFireballTexture = Content.Load<Texture2D>("playerFireball");
Since we need the player position for the fireball creation we'll need to add a property to the Player class so we can access the position from our game class. In the Player.cs add the following below the position definition:
public Vector2 Position
{
get
{
return position;
}
}
Now we can get the current player position. We'll add another key press test to the UpdateInput in the Game class that will create a fireball and add it to the list:
if (gamePadState.Buttons.A == ButtonState.Pressed ||
gamePadState.Triggers.Right >= 0.5f ||
keyState.IsKeyDown(Keys.Space))
{
Fireball shot = new Fireball(playerFireballTexture,
new Vector2(playerShip.Position.X, playerShip.Position.Y - 10.0f),
300.0f);
playerFireballList.Add(shot);
}
If you run the program now and try firing with the spacebar you'll see something like the following:

What we're seeing here goes back to the keyboard events not being event driven, but polling. When we press the fire button to create a fireball we might hold it down for maybe half a second. But our game loop is updating at sixty times per second, so holding the key down for half a second will create about thirty fireballs. This is because we are just polling the keyboard and gamepad at each update. One common solution to this is to save the previous Keyboard state, so when we update we can see if the key was pressed in the last loop update or if it is a new key press. But we'd like to have something here where if the player holds down the fire button the player will continue to attack, like firing every three seconds. To do this we'll create a buttonFireDelay variable. It will work by at every update we'll subtract from it how much time has passed since the last update and when we press the attack we'll set it to three seconds. We also won't let the keyboard fire key be registered until three seconds is up. This means when the fire button is pressed the buttonFireDelay will be set to three seconds, and we won't be able to fire again until three seconds is up. So in the Game class add the following variable:
float buttonFireDelay = 0.0f;
And in the update loop we'll get how much time has passed since the last update and subtract it from the buttonFireDelay. Add the following to the Update loop:
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
buttonFireDelay -= elapsed;
Then change the UpdateInput attack part to:
if (gamePadState.Buttons.A == ButtonState.Pressed ||
gamePadState.Triggers.Right >= 0.5f ||
keyState.IsKeyDown(Keys.Space))
{
if (buttonFireDelay <= 0.0f)
{
Fireball shot = new Fireball(playerFireballTexture,
new Vector2(playerShip.Position.X, playerShip.Position.Y - 10.0f), 300.0f);
playerFireballList.Add(shot);
buttonFireDelay = 0.25f;
}
}
In this modification we only allow the player to fire if the buttonfireDelay is less than or equal to zero. When the player does fire the buttonFireDelay is set to 0.25 so we won't be able to fire again for a quarter of a second. If you run the game now the player will fire normally:

That sets up our player firing. Next we’ll give the player something to shoot at.
Creating Enemies
One of the largest issues when designing games are the enemy characters the player interacts with. Usually AI is a big issue for enemies as is collision detection, which we'll talk more about later in the chapter. For the moment we'll just make some basic enemies to interact with.
Our enemies will be pretty simple, just sprites that comes down the screen. They'll also have the ability to move left and right as they travel down, and fire at the player. For the collision detection we'll test if the player's fireballs hit an enemy or if an enemy or enemy's fires hit the player. (Note that two extra features originally added for the enemies were an inheritance hierarchy for the enemies: having a base enemy class that other more specific enemy types inherited from (this is an object-oriented way of doing things.) The other feature was reading in an xml file that had info for all of the enemies, when and where they are created for the game. But putting in the class inheritance hierarchy and reading xml was difficult for several students and slowed things down, so versions of the ShipFighter game with these features would be a good project but we won't discuss them in the text.)
Enemy Project
Now we’ll start adding the enemies to our project. The first thing to do is add some new resources for the enemies. Add the pictures blueEnemy.png, greenEnemy.png, and enemyFireball.png to the Content folder of the ShipFighter project. Then create a new source file for the enemies, we'll call Enemy.cs. Here is the code for the enemy class:
class Enemy
{
Vector2 position;
Texture2D picture;
float speed = 150.0f;
float deltaX = 0.0f;
float xLength = 0.0f;
float xStart = 0.0f;
bool firingActive = false;
bool firing = false;
float fireSpeed = 1.0f;
float totalTime = 0.0f;
public bool FiringActive
{
set { firingActive = value; }
}
public bool Firing
{
set { firing = value; }
get { return firing; }
}
public Enemy(Texture2D picture, Vector2 startPosition, float speed )
{
this.picture = picture;
position = startPosition;
this.speed = speed;
}
public void SetAcrossMovement( float deltaX, float xLength )
{
this.deltaX = deltaX;
this.xLength = xLength;
xStart = position.X;
}
public Vector2 Position {
get { return position; }
}
public void Draw(SpriteBatch batch)
{
batch.Draw(picture, position, null, Color.White, 0.0f, new Vector2(
40.0f, 20.0f ), 1.0f, SpriteEffects.None, 0.0f);
}
public void Update(GameTime gameTime)
{
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
position.X += deltaX * elapsed;
if (Position.X < xStart - xLength || Position.X > xStart + xLength)
deltaX *= -1.0f;
position.Y += speed * elapsed;
if (firingActive)
{
totalTime += elapsed;
if (totalTime > fireSpeed)
{
totalTime = 0.0f;
firing = true;
}
}
}
}
Let's go through this class. The first variables we have for the enemy are pretty straightforward:
Vector2 position;
Texture2D picture;
float speed = 150.0f;
Just a position on the screen where the enemy currently is, a Texture2D to hold the sprite for the enemy, and a speed (still in pixels per second) of how fast the enemy is moving down the screen. These variables are set in the constructor for the enemy:
public Enemy(Texture2D picture, Vector2 startPosition, float speed )
{
this.picture = picture;
position = startPosition;
this.speed = speed;
}
When we create an enemy we have to give it a sprite, start position, and speed. The next few variables are for moving the enemy left and right across the screen:
float deltaX = 0.0f;
float xLength = 0.0f;
float xStart = 0.0f;
The deltaX is how much the enemy moves horizontally at each update (again in pixels per second.) The next two variables handle how far across the screen it can move. We don't want the enemy to move completely left and right across the entire screen, so we have xLength, which is how far it can move left or right and xStart which is the start position for the x. So if an enemy has an xStart of 200 and an xLength of 50 it will move left and right across the screen between 150 and 250 (at a speed of deltaX). You can see how this works in the Update method for the enemy, which we'll cover in a moment. The variables are set in the SetAcrossMovement method:
public void SetAcrossMovement( float deltaX, float xLength )
{
this.deltaX = deltaX;
this.xLength = xLength;
xStart = position.X;
}
Note the xStart is just the current position of the enemy when this method is called.
The last few variables are to handle the firing of fireballs (or in this case lasers) by the enemy:
bool firingActive = false;
bool firing = false;
float fireSpeed = 1.0f;
float totalTime = 0.0f;
First we have two bools about firing. The firingActive is if the current enemy can fire at all. If it is true the enemy will start firing and if it's false it won't fire at all. The bool “firing” is if the enemy has firingActive, if it is firing at the current update. If an enemy has firingActive then firing will toggle true and false based on if the enemy is currently firing. The fire speed is what frequency the enemy is firing at. At 1.0f this means the enemy will be firing once a second. The totalTime is just an internal counter for timing the firing. We activate firing for an enemy through the following property:
public bool FiringActive
{
set { firingActive = value; }
}
We just set this true or false from somewhere in the game to let an enemy start firing or not. The next property has to do when we fire:
public bool Firing
{
set { firing = value; }
get { return firing; }
}
Note there's no method here to actually fire. When we have an enemy fire it will create a new fireball object inside of our Game, but not in the enemy object. So in the Game object we'll test at each update if the enemy if firing. If it is we'll create a new fireball there and set the firing flag here back to false. This will make more sense when we look at the Game1.cs in a bit.
That sets up the basic variables for our enemies, the next things we need are a draw method and an update one. For the drawing we'll just take in a spriteBatch and use it to draw the enemy at its current position:
public void Draw(SpriteBatch batch)
{
batch.Draw(picture, position, null, Color.White, 0.0f, new Vector2( 40.0f,
20.0f ), 1.0f, SpriteEffects.None, 0.0f);
}
The Update loop will be a little more complex. The first line just gets the amount of time that has passed since the last update in seconds, to use in our movement calculations:
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
Next we'll move the player left or right using the deltaX and the elapsed time:
position.X += deltaX * elapsed;
Then we'll test if the player has moved enough to the left or right to warrant switching directions:
if (Position.X < xStart - xLength || Position.X > xStart + xLength)
deltaX *= -1.0f;
Multiplying deltaX by negative one changes its sign and causes it to move the opposite direction.
Next move the enemy down the screen based on its speed:
position.Y += speed * elapsed;
That takes care of the movement of the enemy. Next we need to calculate if it should be firing or not:
if (firingActive)
{
totalTime += elapsed;
if (totalTime > fireSpeed)
{
totalTime = 0.0f;
firing = true;
}
}
This is really simple. We just say if the enemy is currently firing (firingActive is true) then add the time that has elapsed from this update to the current time. If this total time is more than the fireSpeed than we should fire, which just means setting firing to true. Then we reset the totalTime to zero so we can start counting again.
This is the class for our enemies, now let's add them to the Game. We're going to be adding two basic enemy types to the game, a green enemy type that moves across the screen and a blue enemy type that fires at the player. In the Game1.cs before the player class go ahead and put the following enum in:
public enum EnemyType
{
green,
blue
}
This enum will be handy when creating enemies since it will make clear if we are talking about the green or blue kind. Next let's add some enemies to Game1.cs:
Remember the four steps to adding something to our game:
1. Declare it
2. Initialize it
3. Add it to the Draw loop
4. Add it to the Update Loop
So first we'll declare some variables for our enemies. We'll need a list to hold all of our enemies and a list to hold all of the enemy fireballs that the blue ones shoot. We'll also need textures to hold the sprites for the green enemy, blue enemy, and the enemy fireballs (and we'll throw in a random number generator called rnd for use later). In the game class add the following variables:
List<Fireball> enemyFireballList = new List<Fireball>();
// List of enemies
List<Enemy> enemyShipList = new List<Enemy>();
Texture2D enemyTextureGreen;
Texture2D enemyTextureBlue;
Texture2D enemyFireballTexture;
Random rnd = new Random();
The two lists are initialized there, but we need to load in the textures. To initialize the sprites in the LoadContent method add the following:
enemyTextureGreen = Content.Load<Texture2D>("greenEnemy");
enemyTextureBlue = Content.Load<Texture2D>("blueEnemy");
enemyFireballTexture = Content.Load<Texture2D>("enemyFireball");
We have everything initialized, so let's draw them. To draw the enemies we'll go through each item in the enemy list and enemy fireball list and call their draw method:
foreach (Fireball f in enemyFireballList)
f.Draw(spriteBatch);
foreach (Enemy e in enemyShipList)
e.Draw(spriteBatch);
That's pretty straightforward, next we need to add them to the Update loop. To update the enemies and enemy fireballs we'll just call their update method, and like the player fireballs we'll check both of them to see if they've gone off screen and out of the game. If they're out of the game we'll delete them from their list. And we'll also want to create any enemy fireballs if any of the enemies are firing. So for each enemy if it is firing we'll create a new enemy fireball and add it to the list:
for (int i = 0; i < enemyShipList.Count; i++)
{
enemyShipList[i].Update(gameTime);
if (enemyShipList[i].Firing)
{
Fireball fireball = new Fireball(enemyFireballTexture,
new Vector2(enemyShipList[i].Position.X + 10.0f, enemyShipList[i].Position.Y + 30.0f), -300.0f);
enemyFireballList.Add(fireball);
enemyShipList[i].Firing = false;
}
if (enemyShipList[i].Position.Y > 900.0f)
enemyShipList.RemoveAt(i);
}
for (int i = 0; i < enemyFireballList.Count; i++)
{
enemyFireballList[i].Update(gameTime);
if (enemyFireballList[i].Position.Y > 900.0f)
enemyFireballList.RemoveAt(i);
}
There we have it, all the enemies are setup for use in the game. Now we need a way to create them. For the moment we'll just use keys on the keyboard to create them. If the C key is pressed we'll create a green enemy and if the D key is pressed we'll create a blue. We'll need a function that creates enemies, so add the following to the Game class:
public void CreateEnemy(EnemyType enemyType)
{
Random r = new Random();
int startX = r.Next(800);
if (enemyType == EnemyType.green)
{
Enemy enemy = new Enemy(enemyTextureGreen, new
Vector2(startX, -100), 150.0f);
enemy.SetAcrossMovement((float)startX / 800.0f * 250.0f, 50.0f);
enemyShipList.Add(enemy);
}
if (enemyType == EnemyType.blue)
{
Enemy enemy = new Enemy(enemyTextureBlue, new Vector2(startX,
-100), 150.0f);
enemy.Firing = true;
enemyShipList.Add(enemy);
}
}
This function takes in an EnemyType type (green or blue from the enum.) Then it creates a random number for the x start position:
int startX = rnd.Next(800);
The rnd is a Random number generator and the .Next(800) means to return a number in the range 0-800. Then we use this start position for the X and create a new enemy. We'll create either a green enemy that we set to move left and right across the screen using the SetAcrossMovement we described earlier or a blue enemy that we set FiringActive to true to get it to start firing. Now we just need to add some more cases to the updateInput function:
if (keyState.IsKeyDown(Keys.C))
if (buttonFireDelay <= 0.0f)
{
CreateEnemy(EnemyType.green);
buttonFireDelay = 0.25f;
}
if (keyState.IsKeyDown(Keys.D))
if (buttonFireDelay <= 0.0f)
{
CreateEnemy(EnemyType.blue);
buttonFireDelay = 0.25f;
}
These two just check if the C or D is pressed and creates an enemy. If you run the game and hit the C or D keys you'll see enemies fill up the screen.

This all looks nice enough, but notice if you move the player ship around it isn't colliding with anything, everything is acting very independently. We need to put in collision detection, which we'll do next.
Collision Detection
Collision detection is a very famous problem, not just for video games, but for computer science in general. The problem is given a collection of moving objects, test if any of them have collided (or will collide) with each other. This sounds simple enough, but in practice it can become very difficult; in a typical game a huge percent of the CPU time is spent on collision detection. Entire books have been written on the subject. We'll just talk about a few basic concepts here.
The first thing to know about collision detection is when we test to see if two objects intersect we don't do a full detail test first. If we have two 3D models, each with thousands of polygons doing a full test (testing each polygon to see if intersects with any other polygon) to see if the models intersect would be very expensive. We first surround each object with a simple geometric shape, and then test the basic shape to see if they collide. One of the popular simple shapes is a bounding sphere. If each object is contained in a sphere then collision detection becomes simpler. To calculate an intersection we just test the distance between the two objects and see if it is less than the sum of their radii:
if( (position1 – position2).Length() > radius1 + radius2 )
true if they intersect
Another popular method is to use boxes, or more specifically axis-aligned bounding boxes (aabbs). An aabb is a large box that contains an object, with each edge of the box parallel with an axis of the coordinate system. This kind of collision detection is good too, but we'll use the bounding spheres.
Getting back to our game, we're going to do three things with the collision detection:
Detect if the enemy is hit by a player fireball, and if so delete the enemy and the fireball.
Detect if the player is hit by a an enemy fireball, if it is have it blink for a few seconds.
Detect if the player collides with an enemy. If so delete the enemy and have the player blink for a few seconds.
The player blinking is the player going into a recovery state. Later when we track the number of lives the player has we'll set it up so if the player gets hit it loses a life but then becomes invincible for a few seconds, which we'll show by having it blink.
First let's modify the enemy class so it will take in a list of player fireballs and see if any of them hit it. To do this we'll need a radius of the enemy ship, so add the following variable to the enemy class:
float radius = 40.0f;
public float Radius
{
get { return radius; }
}
Why do we set a radius of forty ourselves, instead of calculating it from the sprite? Sometimes we want to adjust the collision detection to make it a bit more sensitive so things collide easier or looser to make the collisions more strict (such as wanting the fireball to have to hit an enemy near the center of it to count as a collision.) For the fireballs we'll treat them as points, we won't bother setting any radius for them. Add the following to the enemy class:
public int CollisionBall( List<Fireball> fireballList )
{
for( int i = 0; i < fireballList.Count; i++ )
{
if ((fireballList[i].Position - position).Length() < radius)
return i;
}
return -1;
}
This takes in fireball list and then checks each one to see if it collided with the player. If a fireball does intersect with the player it returns the index into the list of the fireball, otherwise it returns -1. In the update method in the Game class where we iterate through every enemy we use this by adding the following:
int collide = enemyShipList[i].CollisionBall(playerFireballList);
if (collide != -1)
{
enemyShipList.RemoveAt(i);
playerFireballList.RemoveAt(collide);
}
This does what we said, it gives the enemy the playerFireballList and if one of them hit it will delete the fireball and the enemy. This takes care of the first case, next we need to handle the player colliding with an enemy ship. To do this we need to add a function to test collision to the player class, and the functionality to make it go into a recovering state. First we'll add:
float radius = 50.0f;
float blinkTime = 0.0f;
float blinkTimeTotal = 0.0f;
bool blinkOn = false;
bool recoveringActive = false;
const float recoverLength = 3.0f;
The radius is used for collision detection, the rest for the recovering state. The recovering state will work like this: when the player collides with something the recoveringActive bool will be set to true and it will stay true for the amount of time in recoverLength. While we are recovering the blinkOn bool will represent if we are currently in the on or off blink state and will decide if we should draw the player. The blinkTime will track how much time has passed since we last changed blinkOn, when it gets to a quarter second we toggle the blinking. The blinkTotalTime tracks how much time has passed when we started recovering and when it hits the recoverLength we'll set the recovering to false. This is clearer if you look at the new code for the Update method for the player:
if (recoveringActive)
{
const float blinkTimeSlice = 1.0f / 15.0f;
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
blinkTime += elapsed;
blinkTimeTotal += elapsed;
if (blinkTimeTotal > recoverLength)
recoveringActive = false;
else
{
if (blinkTime > blinkTimeSlice)
{
blinkOn = !blinkOn;
blinkTime = 0.0f;
}
}
}
Here we take the time from the last update and add it to the blinkTime and blinkTimeTotal. If blinkTimeTotal is greater than the recovery length we turn the recovering (blinking) off. Else we just test if enough time has passed to toggle the current state of the blink – visible or invisible.
Next we need a method for the player to test for collisions with other objects. To the Player class we add:
public bool CollisionTest(Vector2 point, float radius)
{
if ((point - position).Length() < this.radius + radius)
{
if (!recoveringActive)
{
recoveringActive = true;
blinkTimeTotal = 0.0f;
}
return true;
}
return false;
}
This method takes in a point and a radius and does our basic bounding sphere calculation to test for a collision. If we have a collision and we are not currently in a recovery state we send the player into the recovering state by setting recoveringActive to true and resetting the blinkTimeTotal back to zero. The function returns if we had a collision true or false.
To use this for if the player gets hit with an enemy fireball we'll change the following to the main Update loop in our Game.cs:
for (int i = 0; i < enemyFireballList.Count; i++)
{
enemyFireballList[i].Update(gameTime);
playerShip.CollisionTest(enemyFireballList[i].Position, 20.0f);
}
In this update we go through every enemy fireball and test to see if it collided with the player. The player's collision test will send it into its recovery state if it has.
Lastly we'll test to see if any enemy collided with the player, and if so delete it and send the player into the recovery state. To do this we'll add a little to our enemy collision code from the Update method in the Game:
int collide = enemyShipList[i].CollisionBall(playerFireballList);
if (collide != -1)
{
enemyShipList.RemoveAt(i);
playerFireballList.RemoveAt(collide);
}
else
if (playerShip.CollisionTest(enemyShipList[i].Position, enemyShipList[i].Radius))
{
enemyShipList.RemoveAt(i);
}
else if (enemyShipList[i].Position.Y > 2000.0f)
enemyShipList.RemoveAt(i);
This is the same as before, but with the addition of the else clause. Here we test each enemy to see if it hits the player, if it does it gets deleted and the player's CollisionTest takes it to the recovery state. We also put in a little test to see if the enemy is far off screen, and if it is we won't see it in the game anymore and we'll delete it.
If you run the game you'll find all of the collision detection working. When we fire at enemies they disappear and the player reacts to being hit by other enemies. One last thing to do is to have the enemies be created in a slightly better way than just through keyboard presses.
One simple way to do this is to just use a timer function. We'll just track how much time has passed in the game total and at certain intervals create new enemies. Specifically, in the game class we'll add the following variable:
float totalTime = 0.0f;
and in the Update loop we'll add to it:
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
totalTime += elapsed;
Then we'll add a little function:
public void CreateEnemyTime()
{
if (totalTime > 1.0f && totalTime < 1.01f)
CreateEnemy(EnemyType.blue);
if (totalTime > 2.2f && totalTime < 2.21f)
for (int i = 0; i < 4; i++)
CreateEnemy(EnemyType.green);
if (totalTime > 7.2f && totalTime < 7.21f)
for (int i = 0; i < 7; i++)
CreateEnemy(EnemyType.blue);
}
And add a line in the Update loop to call it. This is pretty simple, just checking the total time and creating enemies when enough time has passed. Again, look on xnagamemaking.com to see a more advanced version of this.
Summary
That wraps up putting enemies in the game. We almost have a fully featured game, but there are still a few things to take care of. In the next chapter we'll add some splash screens, HUD text, and explosion effects.
