# How to limit speed while still adding external forces

I have a ship with a single thruster in space (no friction). My ship uses integration on every update, like this:

(PSEUDO CODE)

Update() {
Velocity += Acceleration
Velocity = Min(Velocity, MaxSpeed)
Position += Velocity
Acceleration = 0
}


Any force that interacts with the ship will accelerate it:

Accelerate(f) {
f /= Mass
Acceleration += f
}


Finally this is how I thrust the ship:

Thrust() {
f = MaxThrustPower * Angle (cos/sin)
Accelerate(f)
}


Like this I can accelerate my ship thrusting until MaxSpeed is reached.

The problem is that I also accelerate the ship with other forces line Gravity pulls, collisions, friction fields, etc. And all those forces, as they also add to velocity, they are also being truncated by the MaxSpeed limit.

At the other hand, once I have reached MaxSpeed, I cannot thrust any more to change my direction.

(This is a 2D game, not an exact simulator)

How can this be handled properly?

Thanks!

Just change the order of your operations, and make sure you use 2d vector values for everything (force, acceleration, velocity, position.)

Your clamping should be done at the last step, after you have accumulated all the forces, calculated the acceleration, applied the acceleration.

1. accumulate all forces
2. acceleration = force / mass
3. velocity += acceleration * dt
4. clamp the magnitude of the 2d velocity vector
5. position += velocity * dt

To do the clamping:

if velocity.length() > maxvel
velocity = velocity.normalized() * maxvel


UPDATE

Yes, by clamping the velocity, you will see that further acceleration in the direction of the currently maximum velocity vector will have no effect. But that's the cost of adding that artificial clamp.

Simulations in an atmosphere (airplane instead of rocket) have the benefit of a soft velocity limit:

Because air-drag goes up with the square of the velocity, even the most powerful engine will at some point stop accelerating. Also gravity can't overcome the "terminal velocity" once the drag forces equal the gravity force.

In space there is no such limit, so acceleration continues. (If we disregard the effects at near light speed of course.) So a max speed in space makes little sense in physics terms, and is more like a game-play thing.

• Hi Bram, thanks for your reply. I don't think I'm getting it. Let's say my MaxSpeed (max length for the velocity vector) is 2 and that I'm accumulating: THRUST of length=2 and a GRAVITY PULL of length 2.8, both in same direction. Even if I accumulate and then accelerate the ship (dividing forces by mass=1 for example), the length of the velocity will be limited. I'm using 2D vectors for all my forces and my clamp function is exactly the same than yours, this was just a quick pseudo-code. Thanks! – Eduardo G.R. Feb 28 '19 at 1:45

Ok so I found that the solution to my problem was a new approach to the problem.

First I removed the overall velocity length limit in the update function. At this point all forces will be able to apply on my ship, from thrusting to black holes, no limits.

The thruster is a vector with a direction and the force to be applied on that direction. The thruster also has a max power value that will limit the amount of force it can apply until the max speed is reached.

Every time I fire the thrust I need to keep the applied force proportional to the new desired velocity and relative to the current velocity.

And as I am using Steering Behaviours I will calculate the new thrust vector like this (PSEUDO CODE)

  steer = desiredVelocity - ship.velocity
steer.limit(maxThrustPower)

// Thrust and direction settings
desireStrength = steer.length;
rotorAngleDiff = Math.abs(ship.rotorAngle - steer.angle);

// Start rotating the ship
ship.rotateTo(steer.angle);

// Fire thrust: **n** and **k** are 0.01 and good for my game scale
if (desireStrength > n && rotorAngleDiff < k) {
ship.thrust(desireStrength);
}


It is working perfect now!! Even combining different steering behaviours.

In case someone likes to have working demo in JavaScript just ask.