Xbox LIVE Indie Games
Banner of Game Development Tutorial

adding enemies

Add moving objects for the player to shoot at

 

 

We’re flying through the clouds with the greatest of ease – but what is a game without a challenge? It’s time to add some other characters that are flying, too; we have an enemy graphic ready-made for this purpose. It’s up to you to create a class that can represent these flying enemies, then add them to the game loop the same as you have for the player and the backgrounds.

The enemies will be represented by an Animation and will have a Position, the same as the player does, only they’ll move from right to left. And we’ll need more than one alive at the same time, so we’ll have to manage a list. Finally, we’ll throw in a bit of a twist, and have them appear at random vertical positions when they come in. Ready? Let’s go!

Add a new class to your project by pressing SHIFT + ALT + C, and typing in the name Enemy.cs. Press ENTER.

inside enemy.cs

We’re inside our brand-new enemy class. Let’s get to work on the basics. Delete all the using statements at the top, and replace them with the following lines:

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

Now, as we did in our other classes, we’ll set up all the data we’ll need and stub in our standard Initialize(), Update() and Draw() methods to fill in later.

Place your cursor just after the { mark inside the Enemy class. Add a new line and add the following lines:

// Animation representing the enemy
public Animation EnemyAnimation;

// The position of the enemy ship relative to the top left corner of thescreen
public Vector2 Position;

// The state of the Enemy Ship
public bool Active;

// The hit points of the enemy, if this goes to zero the enemy dies
public int Health;

// The amount of damage the enemy inflicts on the player ship
public int Damage;

// The amount of score the enemy will give to the player
public int Value;

// Get the width of the enemy ship
public int Width
{
get { return EnemyAnimation.FrameWidth; }
}

// Get the height of the enemy ship
public int Height
{
get { return EnemyAnimation.FrameHeight; }
}

// The speed at which the enemy moves
float enemyMoveSpeed;

public void Initialize()
{
}

public void Update()
{
}

public void Draw()
{
}

This is starting to get pretty familiar. Only a few surprises here, such as a few interesting variables for health, score, and damage. We’ll get to those in a later step, but we need to focus on the basics first: managing animation, and position. Let’s start with the Initialize() method.

Replace the Initialize() method you just stubbed in with this version:

public void Initialize(Animation animation,Vector2 position)
{
// Load the enemy ship texture
EnemyAnimation = animation;

// Set the position of the enemy
Position = position;

// We initialize the enemy to be active so it will be update in the game
Active = true;


// Set the health of the enemy
Health = 10;

// Set the amount of damage the enemy can do
Damage = 10;

// Set how fast the enemy moves
enemyMoveSpeed = 6f;


// Set the score value of the enemy
Value = 100;

}

There are those score, health, and damage variables again. They’re going to come in handy in a future step when we start implementing collision and damage. For now, let’s stay on track and move onto the Update() method which will manage moving the enemies and deciding if they’ve gone off the edge of the screen.

Replace the Update() method you just stubbed in with this version:

public void Update(GameTime gameTime)
{
// The enemy always moves to the left so decrement it's xposition
Position.X -= enemyMoveSpeed;

// Update the position of the Animation
EnemyAnimation.Position = Position;

// Update Animation
EnemyAnimation.Update(gameTime);

// If the enemy is past the screen or its health reaches 0 then deactivateit
if (Position.X < -Width || Health <= 0)
{
// By setting the Active flag to false, the game will remove this objet fromthe
// active game list
Active = false;
}
}

The top three lines are familiar – we need to move the enemy by their fixed rate, then send the new Position to its Animation and update it. Finally, we are checking to see if the position is past the left edge of the screen. The reference to –Width means a value equal to -1 * Width, which is the width of the enemy graphic. This will happen when the enemy graphic’s rightmost pixel touches the left hand side of the screen, so the rest of the graphic will have smoothly slid off the edge of the screen by this time.

Setting Active = false; is what will get rid of the enemy when it slides off the screen. We’ll do the removing based off this flag in the Game1 class. On to drawing!

Replace the Draw() method you just stubbed in with this version:


public void Draw(SpriteBatch spriteBatch)
{
// Draw the animation
EnemyAnimation.Draw(spriteBatch);
}

A simple draw call, just like the way we draw Player. They’re using the same Animation code, and that’s the value of encapsulating functions like animation in their own classes – everything can use the same basic functions.

We’re done with our Enemy class for now – we need to get them set up in our game loop, so it’s off to Game1.cs for the rest of this step.

Switch to the Game1 class by double-clicking the Game1.cs file in the Solution Explorer in Visual Studio.

inside game1.cs

We’re back inside our Game1 class. Now, if we were just interested in a single enemy like we have a single player, things would be pretty simple. We’d add one Enemy class and get it into the Draw() and Update() loops, and be done!

However, in Shooter, there are a lot of enemies. We want to be able to track as many as we want, all moving at the same time.

To do this, we need something like an array – we’ll use a special class that acts like an array but can grow and shrink automatically to fit any number of objects we want (within a certain limit). It’s called a List and setting it up isn’t too hard. It also behaves like an array at times; we can walk through it using for loops just like we do with arrays.

Look for the first { mark under the start of the Game1 class, and go just below ParallaxingBackground bgLayer2; you added in the previous step. Add a new line and then add the following:

// Enemies
Texture2D enemyTexture;
List<Enemy> enemies;

// The rate at which the enemies appear
TimeSpan enemySpawnTime;
TimeSpan previousSpawnTime;

// A random number generator
Random random;

We’re not just adding a list of enemies, we’re adding some variables that are going to help control the rate at which we add new enemies, as well as a Random class, which spits out random numbers that we can use any time we like; we’ll use them in this game to mix up the vertical position of enemies when they spawn in so they appear to be coming from everywhere. We’ll need to do some initializing on these new variables.

Look down the code, find the Initialize() method. Inside that method, add these lines:

// Initialize the enemies list
enemies = new List<Enemy> ();

// Set the time keepers to zero
previousSpawnTime = TimeSpan.Zero;

// Used to determine how fast enemy respawns
enemySpawnTime = TimeSpan.FromSeconds(1.0f);

// Initialize our random number generator
random = new Random();

Now, since the enemy has graphics associated with it, we’ll need to add a line to the LoadContent() method, the same as we do for the backgrounds and the player.

Look down the code, find the LoadContent() method. Inside that method, below the bgLayer2.Initialize call, add these lines:

enemyTexture = Content.Load<Texture2D>("mineAnimation");

No problem! Now it’s time to get a little more complicated. We’re going to create our own method called AddEnemy(). This is the method we’re going to call when we’re ready to add a new enemy to the game. It will have to do some initialization and position setting.

To do this, you’ll need some empty space inside the Game1 class, but not inside any other method. Just like when you added UpdatePlayer(), look for the Update() method, find the first { mark underneath the function name. Then, follow it down until you find a corresponding } mark that’s got the same indentation level. Then, go one line below that, make a new line, and you’re ready to go.

Add the following lines to make your new AddEnemy() method:

private void AddEnemy()
{
// Create the animation object
Animation enemyAnimation = new Animation();

// Initialize the animation with the correct animation information
enemyAnimation.Initialize(enemyTexture, Vector2.Zero, 47, 61, 8, 30,Color.White, 1f, true);

// Randomly generate the position of the enemy
Vector2 position = new Vector2(GraphicsDevice.Viewport.Width +enemyTexture.Width / 2, random.Next(100, GraphicsDevice.Viewport.Height -100));

// Create an enemy
Enemy enemy = new Enemy();

// Initialize the enemy

enemy.Initialize(enemyAnimation, position);

// Add the enemy to the active enemies list
enemies.Add(enemy);
}

This method doesn’t do too much that’s different, except the randomization of the position.Y value – the 100 values are tightening the actual area that the enemy is allowed to spawn in; not too high and not too low, but closer to the center of the screen.

Now that we have the adding method, we need to make a method that updates all the enemies we have, as well as determines whether or not we should add a new enemy based on the amount of time that’s passed. Just like AddEnemy, get some open space inside the Game1 class.

Add the following lines to make an UpdateEnemies() method:

private void UpdateEnemies(GameTime gameTime)
{
// Spawn a new enemy enemy every 1.5 seconds
if (gameTime.TotalGameTime - previousSpawnTime > enemySpawnTime)
{
previousSpawnTime = gameTime.TotalGameTime;

// Add an Enemy
AddEnemy();
}

// Update the Enemies
for (int i = enemies.Count - 1; i >= 0; i--)
{
enemies[i].Update(gameTime);

if (enemies[i].Active == false)
{
enemies.RemoveAt(i);
}
}
}

This method does two things – first, it checks the GameTime; if a second or more has passed since an enemy has been added, it adds another enemy and resets the spawn timer. Second, it uses a for loop to walk through all of the current enemies and check their Active flag. Remember the check we made in Enemy.cs that would set Active to false if the enemy went off the screen? Now we check this value and do something with it. We call RemoveAt which takes the Enemy object out of the list, deleting it.

By deleting “dead” objects, we keep the amount of memory we use down to a reasonable level. If we didn’t remove the objects at some point, the list would grow forever, eventually maxing out the memory available on your device and causing an error. Conserving memory is important!

Now that we’ve written UpdateEnemies(), we need to get our main game loop to call it at some point, so we need to get it into Update().

Look for the Update() method inside the Game1 class, and after the bgLayer2.Update() call, add the following lines:

// Update the enemies
UpdateEnemies(gameTime);

Finally, we’re down to the last method – like the Player and the Background, we need to draw the enemies inside the Draw() method.

Now, where the enemies draw is up to you, just as long as it’s after the background. If you draw after the Player, the enemies will appear on top of the player’s ship. If you draw before the Player, the enemies will appear behind the player’s ship.

Look for the Draw() method. Inside the method, after you call bgLayer2.Draw(), add these lines:

// Draw the Enemies
for (int i = 0; i < enemies.Count; i++)
{
enemies[i].Draw(spriteBatch);
}

running the game

This was a big step; let’s have a look! Build and run your game by pressing CTRL+F5. You should now see enemy mines moving across the screen like the screenshot below. If you have compiler errors, or you don’t see the mines, don’t worry! We’re at a checkpoint, so you can get an update to your code if you need it.

Screenshot of Shooter Running with Enemies Moving Across the Screen

Next, we’ll teach you how to add collision to your game so that you can hit the enemies for damage.

checkpoint! check your work and get code

We've come a long way - animation, backgrounds, and enemies!

We recommend you take a second to download a fresh copy of the project with the source code synchronized to the end of this step, especially if you're having trouble getting your code to run.

Just close your Visual Studio environment, click on the link below for the platform you're developing on, then unzip the file and open the enclosed .SLN with Visual Studio. You'll be all caught up!

Adding Enemies - Windows Adding Enemies - for Xbox 360

Move on to the next step: Calculating Collision

var gDomain='m.webtrends.com'; var gDcsId='dcschd84w10000w4lw9hcqmsz_8n3x'; var gTrackEvents=1; var gFpc='WT_FPC'; /*<\/scr"+"ipt>");} /*]]>*/
DCSIMG