Thanks for the suggestions. I've only had a little time to work on this, but I'm thinking that I will probably go with a modified version of C3R14.K1L4's idea eventually. I haven't gotten to the point of setting rotation upper limits yet, but I have got the thing working on a 2D plane so far. The first thing I did is create a constant forward thrust (distance per millisecond). I can reduce this if desired as the ship approaches the target point if I want it to stop close to there, or I can just keep the thrust constant so the ship orbits the target point. The second thing I did is set a radians-per-millisecond variable which determines the maximum speed that the ship will rotate over time (so it looks the same on any speed of computer). Increasing this number causes the ship to more tightly orbit the target point, and decreasing it causes the ship to turn more smoothly. The final thing I did is check if the ship is flying in the general direction of the target (by checking if the front of the ship is closer to the target than the back). In that case, I cast the target point onto the ship's x/z plane, and use law of cosines to determine the difference in angle. If that difference in angle is smaller than the maximum angle it is allowed to turn in the number of milliseconds that have past, then it only rotates the smaller amount (this lines the ship up horizontally with the target point).
Here is the source code so far (probably easier to follow than my poor attempt at an explanation
)
SimpleVector com = centerOfMass.getTransformedCenter();
SimpleVector fdir = flightDirection.getTransformedCenter();
float pointDistance = targetPoint.calcSub( fdir ).length();
float centerDistance = targetPoint.calcSub( com ).length();
float turnAngleY = yrpm * (float) milisPast;
if( centerDistance < pointDistance )
{
ship.rotateAxis( ship.getYAxis(), turnAngleY );
}
else
{
SimpleVector initialVector = new SimpleVector( fdir );
initialVector.y = com.y;
SimpleVector directionI = initialVector.calcSub( com )
.normalize();
SimpleVector finalVector = new SimpleVector( targetPoint );
finalVector.y = com.y;
SimpleVector directionD = finalVector.calcSub( com )
.normalize();
// Length of the triangle's third side:
float distC = directionD.calcSub( directionI ).length();
// Y-angle (unsigned):
float angle = (float) Math.acos( (2.0f - (distC * distC))
/ 2.0f );
if( angle > turnAngleY )
angle = turnAngleY;
// Sign the angle:
if( directionD.x > directionI.x )
angle = -angle;
ship.rotateAxis( ship.getYAxis(), angle );
}
com = centerOfMass.getTransformedCenter();
fdir = flightDirection.getTransformedCenter();
SimpleVector trans = fdir.calcSub( com ).normalize();
trans.scalarMul( dpm * milisPast );
ship.translate( trans );
-- EDIT --
I made a simple applet demonstrating this method:
http://www.paulscode.com/source/AutoNavigation/ (
Source Code)
As you can see, the ship has a bias to turn counterclockwise, which could be fixed with a little bit more logic on my part if I so desired.
The next thing I am going to add in is verticle navigation. This will be a bit more tricky, since I don't want the ship to be able to flip upside down. I'm going to take a look at that AI project code and the rotation upper-limit idea, and see if I can modify it for my purposes.
The final thing I want to add in is a tilt to the ship in whatever horizontal direction it is rotating toward (again, this needs to happen smoothly and have an upper-limit). Of course this won't have a positive effect on the ship's flight direction, but it should look more realistic, which is what I'm after. There are a couple of work-arounds I could use to fix this potential problem area. The first option would be to compensate for the verticle drift this causes by choosing a higher upper-limit for verticle rotations around the ship's x-axis. The second option would be to make the ship a child of a dummy object, and tilt the child object but not the parent. That way I could use the parent's "untilted" axis' for vertical and horizontal navigation. I'm not sure which method will look better, so I'll probably try both and see.
--EDIT #2--
Here's something interesting I just noticed. The plane always seems to line up with the target point when flying more-or-less into the screen but never when flying toward the camera. I believe this is due to a small logic error in my code:
if( directionD.x > directionI.x )
angle = -angle;
I forgot to change these vectors into object-space first, so the angle is being signed incorrectly unless the ship is flying in a net +z direction. I'm kind of glad I made this mistake, though, because I could actually use this in my game if I wanted the NPC enemy ships to always align with the user when flying toward the camera (I'd only have to convert the vectors into camera space and reverse the angle's sign for the ships to have that behavior).