Simple Tower

From TRCCompSci - AQA Computer Science
Revision as of 09:37, 15 November 2017 by Admin (talk | contribs) (Creating Enemy in Game1)
Jump to: navigation, search

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.

Creating Enemy in Game1

In the Game1.cs, add the following in the declaration section (look for SpriteBatch spriteBatch;):

        Texture2D enemyTexture;
        Enemy enemy;

In LoadContent, we need to add the following to create the enemy and set its texture & starting postion:

            enemy = new Enemy();
            enemyTexture = Content.Load<Texture2D>("enemy");
            enemy.Initialize(enemyTexture, new Vector2(300, 300));

In Update, add the following to update the enemy and also to set active on a key press:

            if (Keyboard.GetState().IsKeyDown(Keys.H))
            {
                enemy.Active = true;
            }

            enemy.Update(gameTime);

Finally we need to add the enemy to the draw method:

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin();
            enemy.Draw(spriteBatch);
            spriteBatch.End();

            base.Draw(gameTime);
        }

If you test it and assuming you set each coordinate to a different vector, your enemy should move from waypoint to waypoint. It will disappear when it reaches its final destination.

Creating a Bullet