Low acceleration orbits target

Using AIPath.cs

A low acceleration relative to max speed can result in orbiting the move target. This is because the acceleration vector does not have the correct direction.

This is a function I wrote for an unrelated reason, but shows how to pick the correct acceleration vector to reach a particular target using acceleration

thrustIntercept.txt (4.0 KB)

Oh. Fancy. Do you mind explaining what equations and assumptions this is based off?

Currently the AIPath script tries to solve a 3rd degree equation by assuming that the acceleration will change linearly until it reaches the target, and then it tries to minimize the time without using a too large acceleration. But yeah, it is not perfect (it’s a lot better than what it was in 3.x though).

Sure, by the way you actually have the code to run this in the test project I sent you. The scene is ThrustIntercept

http://www.mathcentre.ac.uk/resources/uploaded/mc-web-mech1-9-2009.pdf

// Constant acceleration equations
// u = initial velocity
// a = acceleration
// v = final velocity
// s = displacement
// t = time
//
// v = u + at
// s = .5 * (u + v) * t
// s = ut + .5f * a * t * t
// s = vt - .5f * a * t * t
// vv = uu + 2 * a * s

// Solve for t given a, s, and relative velocity as u
// s = ut + .5f * a * t * t
// .5fatt + ut - s = 0
// Using the quadratic formula
// t = (-u (±) sqrt(u
u - 4 * .5f * a * -s)) / (2 * .5f * a)

Hm… That pdf says that the object has to move along a straight line… but if the initial velocity does not line up with either the final velocity or the direction to the target, then it cannot move only in a straight line.

Also if I am not mistaken, doesn’t this ignore max speed constraints?

In GetThrustInterceptVectorIndependentAxis() I treat each axis independently, so in that regard it is in a straight line. In GetThrustInterceptVector() I combine the axis.

It doesn’t account for max speed, however if you just normalized to max speed every FixedUpdate() it’s the same thing as having a max speed.

The pathfinding target doesn’t move, but in GetThrustInterceptVector() I put the source in the frame of reference of the destination so the math works out as if it wasn’t moving, the result being that moving destinations are supported.

Ah, okay, so it could be separated by axis. Fair enough.
I’ll take a look at this. It’s about the same complexity as my current code, but maybe it works better.

For reference, this is my current code:

I don’t know about how correct your code is, but it’s straightforward to set the acceleration to 1 and cause orbiting by moving the destination around a bit.

I recommend GetThrustInterceptVector() over GetThrustInterceptVectorIndependentAxis() because the latter can exceed the max acceleration since each axis is independent. It also has 1/3 fewer square roots or thereabouts.

If you run my test scene you can move the target around and it will act as you would expect. The math doesn’t assume the fixed timestep either, as the earlier code which did caused jitter rather than resting at the destination.

BTW, if you don’t care about Y (which I don’t think you do) you can still use GetThrustInterceptVector() and just set currentPosition.y = targetPosition.y