# Intelligently move aircraft using curves

I am trying to code a script to move an aircraft entity from point A to point B and at some point in the middle of moving have the aircraft forward vector face Point C (to fire a missile at an enemy entity at C).

I implemented a bezier curve script that takes as input a list of waypoint and tangent handle Vector3 (Tangent handle is angle at point + weight which is represented by the length of the handle) which I plan to use to move the aircraft alone but I have not figured out a good algorithm to determine where to move to and the tangents at those points.

The control points in the img above are the same as my tangent handles.

The conditions are:

1. Aircraft must start at A, waypoint 0 is therefore at A
2. Tangent 0 angle must match Aircraft starting forward vector direction
3. Waypoint N (last waypoint) must be at point B (finishing location).
4. At some Waypoint (1 - N) the tangent must be facing the enemy position C
5. The last tangent must be level with the y = 0 plane (aircraft must be parallel with the ground)

Constraints

1. A,B,B are on the y=10 plane. This does not mean that waypoints in the middle of the movement need

The aim is to get smooth and somewhat natural looking movement, overly sharp changes of direction are undesirable.

My initial implementation was as follows:

Vector3 middleWaypointPosition =
new Vector3((aircraftTransform.position.x + movementLocation.x + enemyTransform.position.x) / 3f,
(aircraftTransform.position.y + movementLocation.y + enemyTransform.position.y) / 3f,
(aircraftTransform.position.z + movementLocation.z + enemyTransform.position.z) / 3f);
Vector3 finishTangent = middleWaypointPosition + (enemyTransform.position - middleWaypointPosition) / 2;
finishTangent.y = 10;
// Add first point - A position, A forward tangent
waypointSequence.addPoint(aircraftTransform.position, aircraftTransform.position + aircraftTransform.forward * 10);
// Second point - Centroid of A, B, C. Tangent is pointing at C
// Last point - position is at B
(movementLocation - attackUnit.transform.position).normalized * 10);


It works somewhat well in most cases but there are a number of edge cases, for instance A and B being at the same position makes the craft move towards the target then suddenly turn back with a 180 degrees turn towards B. There are a number of cases where I observed strange behavior.

Does anyone have any suggestions on how to design this algorithm?

• I would implement something like this by writing AI for the plane that attacks targets and moves toward destinations, rather than blindly following a curve. – jhocking Aug 26 '14 at 18:59

# Fly along circular arcs

You start at x1, moving in the direction v1 and want to end up at x2 facing in v2, then the shortest path (assuming a finite turning radius, which realistically should be proportional to the square of the velocity) takes you along an arc of radius r1around m1, followed by a straight line segment and then another arc of radius r2around m2

Here is an example path. You start at the bottom, facing either a or b, and want to end up top, facing either A or B, and the possible trajectories resulting from the 4 combinations

The circle centers m_i are at x_i +/- r_i*n_i, where n_i is the normal vector, orthogonal to the velocity v_i = (vx, vy), n_i = (vx, -vy)/sqrt(vx*vx + vy*vy).
From there on its just a little trigonometry and handling degenerate cases with multiple solutions. Those articles on tangent lines might be helpful.

Disclaimer: This works well for stationary targets like flying through hoops or visualizing the path but its by far not the best solution to shoot moving targets
Computing the entire path is costly, but if your target is moving, then you will have to update your path at every timestep, discarding all but the first few points from the last computation, so what you effectively doing, is computing where to turn next, or simply the force acting on you, and it depends only on your and your targets current position and velocity.
Searching for 'homing missiles' gets many results on how to do it, for example here.

A simple approach which produces some brutal AI is to use potential fields (Starcraft AI in action using this method)
This is how such a potential threat field could look in your case, based on turning speed and bullet flight time

Now all you need to do is keep the enemy in the white shootable cone, if he is too far away - accelerate to catch up, if he is in your deadzone or behind you - turn to get him back into the white cone. Do the same for all enemies, add their potential fields and move toward the place of least cumulative threat (close by or behind them) to avoid getting shot yourself.

I would add some AI (artificial intelligence) checks. A first thing to do would be to check if the distance to travel, in comparison with the distance to the enemy makes sense to apply the Bezier curves. For example, you could make the weight (i.e.: distance from the end point to the control point of the Bezier curve) depend on the distance travelled and the distance to the enemy. Because right now, the control point "weight" is half the distance to the enemy, which might be way to much in some cases. If the distance to be travelled zero, then don't do anything.

In fact I would even make the AI in that way that it makes sense every time you make a move. Make sure every time you decide the aircraft to move that the move actually would make sense. If the moving depends on a player input, then don't let the player make those senseless moves, by restricting the places where it can fly towards (e.g.: put a restriction on the minimum travelling distance).

Also, something I can think of: make the lengths of the control points vary in that way that they are not to close to each other. If the control points are to close to each other, or the lines (endpoint-control point) intersect with each other, that could cause some strange behaviour in terms of flying: the sharp turns. In general I think it is a good idea to make sure that the line to line distance of these control vectors are not to small. For doing that, take a look here: Shortest distance between two line segments.

After writing this answer, I think that the most interesting restriction is the line to line distance having a minimum value. This would do a great job, except for the ridiculously short traveling distances. This cannot happen in a "normal" way. Moving a tiny bit to the right, without being able to fly sideways, and with the requirement of having to face the same point at the end, is simply impossible to do "normal".