First, you need to define a path. Easiest is to hard-code it as a vector of points, and just offset it by wherever you start following the path.
Second, you must make the enemy move on that path. Easiest is to keep an index into the array, and move towards the point at that index. When you are close enough, increment the index. When the index is the length of the array, you're done with the path.
| using System; |
| |
| namespace flypath |
| { |
| /// <summary> |
| /// Create an instance of class Follow, passing in the initial position of the object |
| /// and its speed in pixels per second. Also pass in an array of Vector2 that describe |
| /// the relative movement of the object. Call Move() each frame, passing in the number |
| /// of seconds since the last frame (typically 0.166667f for 60 Hz) and get back the |
| /// new position of the object. If Move() returns false, it means that the path has |
| /// been completed. |
| /// </summary> |
| public class Follow |
| { |
| Vector2[ path_; |
| Vector2 offset_; |
| float speed_; |
| float t_; |
| float len_; |
| int segment_; |
| |
| public static Vector2[ SomePath = new Vector2[ { |
| new Vector2(-100, -100), // start out going down/left |
| new Vector2(0, -200), // then go down-right until you're right below where you started |
| new Vector2(0, -300), // then go straight down |
| new Vector2(100, -100), // then go right/up |
| new Vector2(0, 0), // then return to "home" |
| }; |
| |
| public Follow(Vector2[ path, Vector2 spawnPoint, float speed) |
| { |
| path_ = path; |
| offset_ = spawnPoint; |
| speed_ = speed; |
| t_ = 0; |
| // Make sure the internal state machine knows we're at the first segment start point |
| EnterSegment(0); |
| } |
| |
| void EnterSegment(int seg) |
| { |
| // the state machine has reached a new segment in the path to follow |
| segment_ = seg; |
| if (segment_ < path_.Length - 1) |
| { // calculate length to go |
| // calculate how long the path is, at our configured velocity |
| len_ = (path_[segment_ + 1] - path_[segment_]).Length(); |
| t_ = 0; // I have not started moving here yet, so I'm at time 0 of this segment |
| } |
| } |
| |
| /// <summary> |
| /// Move the object along the path, given some amount of time has elapsed. |
| /// </summary> |
| /// <param name="dt">The number of seconds that has elapsed since the last call.</param> |
| /// <param name="pos">Returns the new position of the object.</param> |
| /// <returns>false if the path has finished</returns> |
| public bool Move(float dt, out Vector2 pos) |
| { |
| // add to the current time along the path |
| t_ += dt; |
| // if I reached the end of this segment, move to a new segment |
| if (t_ >= len_) |
| { |
| EnterSegment(segment_ + 1); |
| } |
| // calculate my position along the current segment (or, if complete, just return the start point) |
| pos = (segment_ >= path_.Length - 1) ? offset_ : offset_ + path_[segment_] + (path_[segment_ + 1] - path_[segment_]) * (t_ / len_); |
| // return true as long as I'm still following the path |
| return segment_ < path_.Length; |
| } |
| } |
| |
| public class Program |
| { |
| static void Main(string[ args) |
| { |
| Vector2 initPos = new Vector2(300, 600); |
| Follow f = new Follow(Follow.SomePath, initPos, 20); |
| Console.WriteLine("First pos: {0}", initPos); |
| while (f.Move(1, out initPos)) |
| { |
| Console.WriteLine("New pos: {0}", initPos); |
| } |
| Console.WriteLine("End pos: {0}", initPos); |
| return; |
| } |
| } |
| |
| // In this test program, I define my own Vector2, so that I don't have to |
| // link with the entire XNA framework. |
| public struct Vector2 { |
| public Vector2(float x, float y) { X = x; Y = y; } |
| public float X; |
| public float Y; |
| public float Length() { return (float)Math.Sqrt(X*X + Y*Y); } |
| public override string ToString() |
| { |
| return String.Format("{0:0.0},{1:0.0}", X, Y); |
| } |
| public static Vector2 operator +(Vector2 a, Vector2 o) { return new Vector2(a.X + o.X, a.Y + o.Y); } |
| public static Vector2 operator -(Vector2 a, Vector2 o) { return new Vector2(a.X - o.X, a.Y - o.Y); } |
| public static Vector2 operator *(Vector2 a, float s) { return new Vector2(a.X * s, a.Y * s); } |
| } |
| |
| } |
| |
Usage:
Create a Follow for each sprite, passing in the spawn position and speed in pixels per second.
Each frame, call Move(), passing in the amount of time that has passed (ElapsedGameTime).
Out will come the new position. The function will return false if the path is complete.