I’m implementing a 2D game with ships in space.
In order to do it, I’m using LÖVE, which wraps Box2D with Lua. But I believe that my question can be answered by anyone with a greater understanding of physics than myself – so pseudo code is accepted as a response.
My problem is that I don’t know how to move my spaceships properly on a 2D physics-enabled world. More concretely:
A ship of mass m is located at an initial position {x, y}. It has an initial velocity vector of {vx, vy} (can be {0,0}).
The objective is a point in {xo,yo}. The ship has to reach the objective having a velocity of {vxo, vyo} (or near it), following the shortest trajectory.
There’s a function called update(dt) that is called frequently (i.e. 30 times per second). On this function, the ship can modify its position and trajectory, by applying “impulses” to itself. The magnitude of the impulses is binary: you can either apply it in a given direction, or not to apply it at all). In code, it looks like this:
function Ship:update(dt)
m = self:getMass()
x,y = self:getPosition()
vx,vy = self:getLinearVelocity()
xo,yo = self:getTargetPosition()
vxo,vyo = self:getTargetVelocity()
thrust = self:getThrust()
if(???)
angle = ???
self:applyImpulse(math.sin(angle)*thrust, math.cos(angle)*thrust))
end
end
The first ??? is there to indicate that in some occasions (I guess) it would be better to “not to impulse” and leave the ship “drift”. The second ??? part consists on how to calculate the impulse angle on a given dt.
We are in space, so we can ignore things like air friction.
Although it would be very nice, I’m not looking for someone to code this for me; I put the code there so my problem is clearly understood.
What I need is an strategy – a way of attacking this. I know some basic physics, but I’m no expert. For example, does this problem have a name? That sort of thing.
Thanks a lot.
EDIT: Beta provided a valid strategy for this and Judge kindly implemented it directly in LÖVE, in the comments.
EDIT2: After more googling I also found openSteer. It’s on C++, but it does what I pretended. It will probably be helpful to anyone reaching this question.
It’s called motion planning, and it’s not trivial.
Here’s a simple way to get a non-optimal trajectory:
If you want a quick and dirty approach to an optimal trajectory, you could use an iterative approach: Start with the non-optimal approach, above; that’s just a time sequence of thrust angles. Now try doing little variations of that sequence, keeping a population of sequences that get close to the goal. reject the worst, experiment with the best — if you’re feeling bold you could make this a genetic algorithm — and with luck it will start to round the corners.
If you want the exact answer, use the calculus of variations. I’ll take a crack at that, and if I succeed I’ll post the answer here.
EDIT: Here’s the exact solution to a simpler problem.
Suppose instead of a thrust that we can point in any direction, we have four fixed thrusters pointing in the {+X, +Y, -X, -Y} directions. At any given time we will firing at most one of the +/-X and at most one of the +/-Y (there’s no point in firing +x and -X at the same time). So now the X and Y problems are independent (they aren’t in the original problem because thrust must be shared between X and Y). We must now solve the 1-D problem — and apply it twice.
It turns out the best trajectory involves thrusting in one direction, then the other, and not going back to the first one again. (Coasting is useful only if the other axis’s solution will take longer than yours so you have time to kill.) Solve the velocity problem first: suppose (WLOG) that your target velocity is greater than your initial velocity. To reach the target velocity you will need a period of thrust (+) of duration
(I’m using Vf: final velocity, Vi: initial velocity, a: magnitude of thrust.)
We notice that if that’s all we do, the location won’t come out right. The actual final location will be
So we have to add a correction of
Now to make the location come out right, we add a period of thrust in one direction before that, and an equal period in the opposite direction after. This will leave the final velocity undisturbed, but give us some displacement. If the duration of this first period (and the third) is t, then the displacement we get from it is
The +/- depends on whether we thrust + then -, or – then +. Suppose it’s +.
We solve the quadratic:
And we’re done.