What is a good technique to enable an object to move between to points in a nice curved motion?
The end position could also be in motion, such as the trajectory of a homing missile.
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It only takes a minute to sign up.Sign up to join this community
Assuming you want this to be a frame-by-frame thing (where the target could even be moving), and not a precomputed trajectory, this is actually incredibly simple:
Every frame, compare the velocity-vector of the missile to the vector (positiontarget - positionmissile); that is, the vector pointing from the missile to the target. Every frame, if the two vectors do not have the same direction, then rotate the veloity-vector a little bit towards the other vector, so every frame the missle gets a little bit closer to looking at its target.
You can determine whether to rotate clockwise or counter-clockwise by looking at the sign of the cross-product between the two vectors.
[Edit] XNA-ish code (I don't have XNA to test this):
//Once a frame: //Get vector spanning from missile to target Vector2 vectorToTarget = target.Position - missile.Position; //Convert to Vector3 to do cross-product Vector3 vectorToTarget3 = new Vector3(vectorToTarget, 0); Vector3 missileVelocity3 = new Vector3(missile.Velocity, 0); //Rotate clockwise/counter-clockwise is determined by sign of cross-product int crossProductSign = Vector3.Cross(missileVelocity3, vectorToTarget3).Z; //Positive cross-product means rotate counter-clockwise, negative is clockwise double rotationAngle = 0; if(crossProductSign > 0) rotationAngle = -0.05; else if(crossProductSign < 0) rotationAngle = 0.05; //I'm not sure how to do rotation in XNA, but the internets tell me it's something like this: missile.velocity = Vector2.Transform(missile.velocity, Matrix.CreateRotationZ(rotationAngle))
Note that, because
rotationAngle has only three possible values, all possible values of
Matrix.CreateRotationZ(rotationAngle) can be cached so you don't have to call it every frame.
There are two possible techniques:
The first technique is to do a frame-based simulation. This is good if you are doing something like a homing missile in gameplay, that does not have to hit your target exactly.
In this case you want to track the object's position and velocity. Each frame look at the direction to the target and the current movement direction, and adjust the velocity appropriately.
If you snap the velocity instantly, your missile will always hit the target. But if you adjust the velocity by a small amount each frame, your missile will curve towards the target - and if it curves slowly enough, the target could dodge it.
The second technique is to use a parametric method. This is useful for animating things where you want to hit your target precisely and predictably. In this case you usually take "time" as your parameter and put it into a function of some kind.
A particularly useful set of functions are the Equations of Motion you learned in highschool physics. By applying these to both axis you can get ballistic trajectories. With a little bit of maths, you can determine the initial parameters to hit a target - even a moving one, if it moves predictably.
XNA also provides a number of interpolation and curved motion functions. Take a look at the documentation for
Vector2 and for
MathHelper. These provide some interpolation functions which you can use and even combine to do interesting things. For example, firing a missile:
Lerp (linear interpolate) your missile's position from its start point to a target position, and also lerp that target position from some initial target to the target object's real (changing) position. This will give you a nice "locking on" effect.
(There are also some functions for producing curves, for example:
Hermite. These are probably harder to use successfully with a moving target, though.)
If you look into "easing" (in the context of animation), you can get some more interesting interpolation functions that can give you interesting effects like acceleration.
Now - you may say that this technique gives some odd results as your target moves around. However in practice, as long as your projectile is moving faster than your target, it usually looks fine. If it is a problem, you should probably be using a frame-based technique anyway.
You may want to look up sine waves or possibly Bezier Curves. I don't know whether the sine wave approach is normal, but I can't see why it would be that poor.
You can take a look at Steering Behaviors, as defined by Craig Reynolds: http://red3d.com/cwr/steer/
This is often used in AI to have NPCs move toward their target.