I am making a defence game. Naturally, this means that there needs to be objects following a path on the screen. I want to make it a strict path from one point to another to another. I could use an array of vertices, but i need some help. Can someone please show me some code that could help me with this? Thanks.
1 Answer
Okay, I gave it a quick test run and it seems to be working on my end. Here's my solution. Imagine your entity has the following members, and you'd like to make the entity follow whatever path is currently set to the path
member variable:
class Entity
{
Vector2 position;
float speed;
List<Vector2> path;
void Update(float elapsed);
}
I started by adding an helper method inside the class that moves the entity towards some goal, and returns true if that goal was reached:
private bool MoveTowardsPoint(Vector2 goal, float elapsed)
{
// If we're already at the goal return immediatly
if(position == goal) return true;
// Find direction from current position to goal
Vector2 direction = Vector2.Normalize(goal - position);
// Move in that direction
position += direction * speed * elapsed;
// If we moved PAST the goal, move it back to the goal
if (Math.Abs(Vector2.Dot(direction, Vector2.Normalize(goal - position)) + 1) < 0.1f)
position = goal;
// Return whether we've reached the goal or not
return position == goal;
}
Using this helper method, following the path is as simple as doing:
public void Update(float elapsed)
{
if(path.Count > 0 && MoveTowardsPoint(path[0], elapsed))
path.RemoveAt(0);
}
Notes
I think the only line that isn't really clear is the following:
Math.Abs(Vector2.Dot(direction, Vector2.Normalize(goal - position)) + 1) < 0.1f
What I'm doing here is checking if the direction before the move, and the direction after the move are opposite. I do this by checking if the dot product between both directions is close to -1 using an epsilon comparison. Another solution that seems to work is replacing the same check by:
Vector2.Distance(direction, Vector2.Normalize(position - goal)) < 0.1f
When I tried it the result was the same. As for the update loop:
if(path.Count > 0 && MoveTowardsPoint(path[0], elapsed))
path.RemoveAt(0);
It's relying on the && operator not bothering to run the second portion of the operation unless the first one is true. So if there's no path, nothing else happens. If there's a path, then MoveTowardsPoint
is called, and its return value is what decides whether we should remove the point from the path list or not.