Sunday, 26 September 2010

Tutorial 5 : Towers

Now that we have something to shoot at, I think it is about time that we start adding in the “Tower” part of our Tower Defence. We will start off by creating a simple base class for the tower and getting it drawn, then we will move on to making it aim at our enemy. I will be leaving shooting, and placement of towers till next time. So, lets begin!

Start off by adding a new class to the project called “Tower.cs”, and make it inherit from the Sprite class :

publicclass Tower : Sprite

{

}

Next we will add in some of the basic fields and properties that all towers will share :

protectedint cost; // How much will the tower cost to make

protectedint damage; // The damage done to enemy's

protectedfloat radius; // How far the tower can shoot

publicint Cost

{

get { return cost; }

}

publicint Damage

{

get { return damage; }

}

publicfloat Radius

{

get { return radius; }

}

All these fields are self explanatory. Next we will add in a simple constructor for our class :

public Tower(Texture2D texture, Vector2 position)

: base(texture, position)

{

}

Notice how we don’t set any values for the tower’s fields, this is because each different tower type will have different costs and ranges and damages etc, so it will be easier if each type of tower sets it’s own values, as you will see later on in the tutorials.

And that’s the basics done, go back into Game1.cs and add the following field :

Tower tower;

Before we can initialize the new tower we first need to add the following texture to the content project :

With that added we can move onto initializing and drawing our tower. In the LoadContent method add the following :

Texture2D towerTexture = Content.Load<Texture2D>("arrow tower");

tower = new Tower(towerTexture, Vector2.Zero);

All this code does is create a shiny new tower in the top left corner of our screen, using the texture we just added.

Now all that’s left is to draw it, so in the draw method just after where we draw our enemy, add the following :

tower.Draw(spriteBatch);

Now if you run the project you should see something like this :

Now we have our tower drawn, we can move on to something slightly more interesting, making the tower aim,

To start with we are going to give our a bigger range just for testing purposes, so go into Tower.cs and in the constructor add the following :

radius = 1000;

Next we will add in a simple helper method to check whether an enemy is in range of the tower :

publicbool IsInRange(Vector2 position)

{

if (Vector2.Distance(center, position) <= radius)

returntrue;

returnfalse;

}

Here we simple check whether the distance from the centre of the tower to the inputted position is within range. With that added we can move onto writing a method that will return the closest enemy to the tower, this will be how we choose what to shoot!

Before we add that we need one more field and property to store the enemy we are targeting. Add this to the top of Tower.cs :

protected Enemy target;

public Enemy Target

{

get { return target; }

}

Now that's sorted, add the following method to the Tower class :

publicvoid GetClosestEnemy(List<Enemy> enemies)

{

target = null;

float smallestRange = radius;

foreach (Enemy enemy in enemies)

{

if (Vector2.Distance(center, enemy.Center) < smallestRange)

{

smallestRange = Vector2.Distance(center, enemy.Center);

target = enemy;

}

}

}

This is where the magic happens, and it’s quite simple really, we loop through every enemy that is currently alive in the level, and if that enemy is closer than the previously found closest enemy, then the enemy is set to be the target.

Right, onto the aiming method, what we do here is find the direction from the tower to the target, and find out what that direction is by using some trigonometry.

For more information about finding an angle from a direction check out Riemers Tutorial.

Without for ado, here is the method :

protectedvoid FaceTarget()

{

Vector2 direction = center - target.Center;

direction.Normalize();

rotation = (float)Math.Atan2(-direction.X, direction.Y);

}

To call this method we simply override the Sprites Update method, and if we have a target, call FaceTarget() :

publicoverridevoid Update(GameTime gameTime)

{

base.Update(gameTime);

if (target != null)

FaceTarget();

}

And that’s our tower class finished for now! Go back to Game1.cs and in the Update method, just after we Update the enemy, add the following :

if (tower.Target == null)

{

List<Enemy> enemies = new List<Enemy>();

enemies.Add(enemy1);

tower.GetClosestEnemy(enemies);

}

tower.Update(gameTime);

Here, we just check if the tower has a target, and if it doesn’t we give it one using the method we added earlier.

And that’s it for now, if you run the project you should see your black dot following the path, with our shiny new tower following his every move!