We’re going to make enemies that follow a predetermined path. A lot of tower defense games get by with just this as far as enemy movement is concerned.
As this series is mainly focusing on algorithms and datastructures, I’m going to skip over anything that isn’t relevant (like drawing stuff).
Setup
We’ll just keep a list of alive enemies:
var enemies = new Array();
And we need an enemy class, with a location and some bits for movement
Enemy = function (position) {
this.position = position;
this.pathIndex = 1; //The index in the path we are moving towards
this.speed = 4; //grid squares / second
}
We also need a path for the enemies to follow, they will start at the first point and move along the path to the last point.
var path = [
new Vector2(0, 3),
new Vector2(3, 3),
new Vector2(3, 5),
new Vector2(6, 5),
new Vector2(6, 2),
new Vector2(4, 2)
];
The position x and y values are in grid units, with a integer (whole) number meaning the middle of that grid square.
Running it
Every game tick we need to move all of our enemies, the code for moving an enemy looks as follows.
The idea is:
- Work out how far we will travel this tick.
- If our target is within this distance then
- Subtract the distance to it from the distance we are travelling this tick
- Move us to our target point
- Target the next point on the path
- Finally, move us the (remaining) distance towards our target
Note: If your enemies may arrive at multiple points in a single tick, then you need to loop the inner part.
In this code, dt is the change of time variable, it contains how much time (in seconds) has passed since the last update. It will usually be 0.0166666s (1/60) as our game is running at 60 FPS
//foreach enemy
for (var i = enemies.length - 1; i >= 0; i--) {
var e = enemies[i];
//How far we will move in this update
var distanceToMove = dt * e.speed;
//A vector from ourself to our target position
var vectorToTarget = path[e.pathIndex].minus(e.position);
//How far away the target is
var distanceToTarget = vectorToTarget.length();
//We assume you'll never move more than one path point in a game tick
//If we will arrive at the target this tick
if (distanceToTarget < distanceToMove) {
e.position = path[e.pathIndex]; //Arrive at the target
e.pathIndex++;
//If we hit the last point on the path, delete ourself
if (e.pathIndex == path.length) {
enemies.splice(i, 1);
continue;
}
//recalculate for the new destination
//Use up some of our movement moving to the path point
distanceToMove -= distanceToTarget;
//Work out the vector to our new target
vectorToTarget = path[e.pathIndex].minus(e.position);
//And our new distance (unused)
distanceToTarget = vectorToTarget.length();
}
//Now move us along the path using our (remaining) movement
e.position = e.position.plus(vectorToTarget.normalize().mul(distanceToMove));
e.rotation = vectorToTarget.angle();
}
We will also spawn enemies periodically, this is easy
//How many seconds between spawning each enemy
var timeBetweenSpawns = 1;
//Time until the next spawn (start 0 so we immediately spawn one)
var timeToNextSpawn = 0;
function gameTick(dt) {
//Count down our timer
timeToNextSpawn -= dt;
//If it expired
if (timeToNextSpawn <= 0) {
//Spawn an enemy
enemies.push(new Enemy(path[0]));
//Reset the timer
timeToNextSpawn += timeBetweenSpawns;
}
}
Mush these together with some code to draw the enemies, grid and path and you get something like this: Running Example