Simple Tower
This tutorial will create a simple tower defence style game. In order not to give too much away, it will only pre-create a single tower and only have a single enemy. For your actual project you will need to position towers, have swarms of enemies.
The Enemy
You will need to create a new class, so click on project & select new class. Obviously give the class the name enemy. You will need to add the MonoGame references at the top of the code (in the using section).
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
No to create a moving enemy you will need to declare some variables within the class. The enemy is going to need a texture to display, but also a path to follow. The best way to represent a path would be to have a Queue of vectors, and each vector would be a waypoint for the enemy:
public Texture2D texture;
Queue<Vector2> path = new Queue<Vector2>();
In order to move the the enemy we will also need to know the current position, the destination, and how to move between the two. We also need a way to start the enemy, so declare a bool called active and set it to false:
Vector2 position;
Vector2 movement;
Vector2 destination;
bool active = false;
When you create an enemy we can write an Initialise method to setup the enemy. This will allow us to set the Texture and Position of the Enemy. This method can also be used to set the path of the enemy. The path.Enqueue lines will add each waypoint into the queue, you will need to set the coordinates for each waypoint:
public void Initialize(Texture2D text, Vector2 pos)
{
texture = text;
position = pos;
movement = new Vector2(0, 0);
path.Enqueue(new Vector2(100, 100));
path.Enqueue(new Vector2(100, 100));
path.Enqueue(new Vector2(100, 100));
path.Enqueue(new Vector2(100, 100));
path.Enqueue(new Vector2(100, 100));
}
Now we need a way of starting the enemy, the easiest way is to create a property to get & set the Active boolean. This will also allow us to run additional code when active is set. So add the property below:
public bool Active {
get{return active;}
set {
active = value;
}
}
So if the value of active is set, we want to see if we have a vector in the path queue. If we do have a vector we want to set that as our destination. Now we have a destination we can work out the movement required to get there:
public bool Active {
get{return active;}
set {
active = value;
if (path.Count() > 0)
destination = path.FirstOrDefault<Vector2>();
Vector2 difference = (destination - position);
movement = difference / Vector2.Distance(destination, position);
}
}
The vector called difference can be calculated by subtracting the current position from the destination vector. If we used this for movement we would instantly jump to that position, so instead we can divide the difference vector by the distance. This will give us a movement vector which we can keep applying to make the enemy move.
Now for the update method for your enemy, create the following method:
public void Update(GameTime gameTime)
{
if (Active)
{
position += movement;
}
}
This will allow your enemy to move to the first destination, however we will need to check when it arrives at its destination. So add the following:
public void Update(GameTime gameTime)
{
if (Active)
{
Vector2 difference = (destination - position);
if (difference.X > -1 && difference.X < 1 && difference.Y > -1 && difference.Y < 1)
{
Console.WriteLine(position + " " + destination);
path.Dequeue();
}
position += movement;
}
}
We can check we have arrived by check the difference between the position and the destination. If the X & Y are between 1 & -1 we should be at the destination. At the moment the destination is removed from the path, but we also need to get a new destination so we can use the Active property to get a new destination:
public void Update(GameTime gameTime)
{
if (Active)
{
Vector2 difference = (destination - position);
if (difference.X > -1 && difference.X < 1 && difference.Y > -1 && difference.Y < 1)
{
Console.WriteLine(position + " " + destination);
path.Dequeue();
if (path.Count == 0)
Active = false;
else
Active = true;
}
position += movement;
}
}
Finally we need to create the Draw method:
public void Draw(SpriteBatch spriteBatch)
{
if (active)
spriteBatch.Draw(texture, position);
}
You should now have an enemy which will move from waypoint to waypoint.