The faster an object goes, the slower it will accelerate, going from 0 to 50 takes a lot less time then going from 50 to 100,

How do I calculate that, though?

EDIT: Extra details,

This specific scenario is about a space ship, here is the code I'm using for giving it a constant acceleration, which I'd like to rewrite so that the faster it goes, the slower it accelerates.

EDIT2: Thanks to Sam Hocevar the code I showed was flawed, I've updated the code.

var dx = this.x - this.destination.x,
    dy = this.y - this.destination.y,
    r = Math.atan2(dx, dy) * -1,

this.speed += this.acc;
if(this.speed > this.maxSpeed){ this.speed == this.maxSpeed; }

this.x = Math.sin(r) * this.speed + this.x;
this.y = (Math.cos(r) * this.speed * -1) + this.y;

Old code.

this.sx += (this.destination.x > this.x) ? this.acc : -this.acc;
this.sy += (this.destination.y > this.y) ? this.acc : -this.acc;

if(this.sx > this.maxSpeed){ this.sx = this.maxSpeed; }
if(this.sx < -this.maxSpeed){ this.sx = -this.maxSpeed; }
if(this.sy > this.maxSpeed){ this.sy = this.maxSpeed; }
if(this.sy < -this.maxSpeed){ this.sy = -this.maxSpeed; }

this.x += this.sx;
this.y += this.sy;

  • 4
    \$\begingroup\$ It should be mentioned that in space, and within the limits of newtonian mechanics, going from 0 to 50 takes exactly the same time as going from 50 to 100. If you want to artificially restrict acceleration because it "feels" better, you will have to add artificial forces that do not exist in the real world. \$\endgroup\$ – sam hocevar May 4 '12 at 11:54
  • \$\begingroup\$ No shit... So in my attempt to make things more realistic I'm actualy making it less realistic? FML... \$\endgroup\$ – Johan May 4 '12 at 12:00
  • \$\begingroup\$ And my suggestion for making it "feel better" is not to add artificial forces and invent your own physics - play with camera, make it shaky, accelerate slower than ship or alike. Just don't mess with physics, the further you step away from real formulas the complicated it gets when you want to implement something else using these values. \$\endgroup\$ – tomsseisums May 4 '12 at 12:12
  • \$\begingroup\$ All those -1 you added indicate something is wrong. The first -1 can be omitted if you compute the direction as destination - position instead of position - destination. The correct way to call atan2 is r = Math.atan2(dy, dx) (notice the argument order). Then the x component is Math.cos(r) and the y component is Math.sin(r) and all the -1's can go away. \$\endgroup\$ – sam hocevar May 4 '12 at 12:44
  • \$\begingroup\$ Thanks @SamHocevar , I've tried getting rid of the -1 before but without success... Thanks :) \$\endgroup\$ – Johan May 4 '12 at 12:59

You have an opposing force called "friction", which is proportional to speed. This is how objects falling in an atmosphere are modeled, for example.

If your impulse force is F, a constant, and you have a mass m, your acceleration is the constant

a = F/m

Let's call the friction force Q, and the acceleration caused by that q. We have that

Q = k*v

where k is a constant (that depends on several things, like material and surface and viscosity and whatnot, but you just choose a number that feels right), and v your current speed.

q = Q/m = k * v / m

The new speed v' will be the timestep times the total acceleration:

v' = v + dt * (a - q) = v + dt * (a - k/m * v)

The new position x' will be the timestep times the current speed:

x' = x + v * dt

P.S. In your code up there, you just have to modify acc before the first computation, subtracting the product of your current speed and some small constant.

  • \$\begingroup\$ I'm probably missing something but there isn't any friction is space, so that would mean k = 0 which then makes a lot of things unnecesary... I'm probably overthinking stuff now, though \$\endgroup\$ – Johan May 4 '12 at 11:36
  • \$\begingroup\$ @Johan Im not sure about it, but this may include aerodynamics(is there on space?), motor power, etc etc. So it's doesnt have to be 0 just because there's no air on the space. \$\endgroup\$ – Gustavo Maciel May 4 '12 at 11:38
  • \$\begingroup\$ There aren't any aerodynamics in space, there are probably other stuff, like the motor power you mentioned... I'm just gonna see how it performs and report back afterwards \$\endgroup\$ – Johan May 4 '12 at 11:50
  • \$\begingroup\$ Johan, helios.gsfc.nasa.gov/qa_sp_ms.html#friction there is friction, but very small. I'd suggest you ask this question on physics.SE first, and then, for game implementation - come here. \$\endgroup\$ – tomsseisums May 4 '12 at 11:55
  • 1
    \$\begingroup\$ Also, wiki.answers.com/Q/How_do_you_calculate_acceleration_in_space not the best place to look for physics answers, but I think the answer is valid. \$\endgroup\$ – tomsseisums May 4 '12 at 12:02

I believe that the proper way to do this is to add a friction force. A force can simply divided by the object's mass to get an acceleration. The simplest variant is a force proportional to the speed or the square of the speed, in a direction opposite to the velocity.

Also your acceleration should have the direction of your ship: as of now, the ship is only accelerating at 45-degree angles which is somewhat weird.

The integration of the position is not very accurate either; look for "Velocity Verlet" for a way to improve accuracy.

Finally, merely adding an acceleration to a velocity does not make physical sense; you probably have a hidden timestep somewhere, it would be better to include it in the calculations.

/* Compute the wanted direction of the ship */
float dx = (this.destination.x - this.x);
float dy = (this.destination.y - this.y);
float d = sqrtf(dx * dx + dy * dy);
dx /= d; dy /= d; /* FIXME: check for division by zero here! */

/* Accelerate towards the destination */
this.sx += this.acc * timestep * dx;
this.sy += this.acc * timestep * dy;

/* Apply friction force with coefficients K1 and K2 */
/* FIXME: ensure that velocity does not change sign due to high friction */
this.sx = (-K1 -K2 * abs(this.sx)) * this.sx * timestep;
this.sy = (-K1 -K2 * abs(this.sy)) * this.sy * timestep;

/* Integrate position */
this.x += this.sx * timestep;
this.y += this.sy * timestep;

Now in order to limit the final velocity you just need to tweak the K1 and K2 values.

  • \$\begingroup\$ I'm not workign with timestamp variables at this time, it's just an update at every tick. Also, what do you mean that in my current setup the ship can only accelerate at 45 degree angle? The acc can be negative, so the ship can go anywhere. I'll try your script out, thanks! \$\endgroup\$ – Johan May 4 '12 at 11:33
  • \$\begingroup\$ @Johan even if timestep = 1.0 it's good practice to have this variable defined somewhere; otherwise the day you decide to use something else you're going to have to check every single place. As for the 45-degree angle, imagine this->acc = 1.0. If the acceleration is positive you'll be always doing this.sx += 1.0 and this.sy += 1.0 and never something with another orientation such as this.sx += 0.75 and this.sy += 1.2. \$\endgroup\$ – sam hocevar May 4 '12 at 11:44
  • \$\begingroup\$ Yeah I see the issue with the 45 degrees, must have been blind while testing it earlier... How do I get the -K1 and -K2 though? I assume they are constants? Also, is d in degrees or radians? (guessing degrees) \$\endgroup\$ – Johan May 4 '12 at 11:48
  • \$\begingroup\$ @Johan You are working with a timestep variable, the only difference is that it has a value of 1. And if position(x,y) = position(x,y) + velocity(x,y) where abs(velocity.x) == abs(velocity.y) it means you're advancing the same distance on both x and y axes, which leads to Sam's observation of going diagonals (at an angle of 45 degs). Do you need to move the ship between two points, A and B with variable acceleration? This is not clear yet and it can make things more complicated. \$\endgroup\$ – teodron May 4 '12 at 11:50
  • \$\begingroup\$ d is the norm of the direction vector from your ship's position to its target, and what you do there is to normalize in order to get a unit direction vector. \$\endgroup\$ – teodron May 4 '12 at 11:51

I think some of the answers here are missing something. I think what you really want is controls and not physics. Let me explain. Control theory explores the mathematics of systems that can sense a value, and control themselves to reach a target value. Examples of this include climate control systems, anti-lock breaking systems in cars, robots, and yes even spacecraft in space.

Physics is what happens to the system due to the laws of nature. In space, there is no friction, and no forces acting on your ship besides the engine so the physical system is very simple:

// Newton's third law
Acceleration = Force / Mass;

// Newton's first law
Velocity' = Velocity + Acceleration * dt
Position' = Position + Velocity * dt

But you additionally have two Control Inputs that influence the system. That is, the angle and force of the ship's engine!

// Engine
Force = Engine_Thrust * [Cos(Engine_Angle), Sin(Engine_Angle)];

So the question you should be asking is: what angle should the engine be pointing at, and how much force should it apply?

That is, we want to find a Control Law, which is a function that determines the engine angles from the position, the velocity and some target:

// Sets the engine thrust and angle based on some target
void ControlLaw(Vector position, Vector velocity, Vector target)
    Engine_Thrust = ?
    Engine_Angle = ?

Right now, you already have a simple control law:

// Sets the engine thrust and angle based on some target
void BangBangControl(Vector position, Vector velocity, Vector target)
    Engine_Angle = atan2(target.x - position.x, target.y - position.y);
    Engine_Thrust = 1.0;

What your control law is saying is * Always point the engine toward the target, at full thrust"*. As you can imagine, what this will cause your space ship to do over time is just to accelerate as quickly as possible toward the target, overshoot the target, and then oscillate around it. What you've invented is something called "Bang Bang Control." What you said you want instead is something more useful: you want the space ship to move toward the target, slow down on approach to the target, and then stop when it reaches the target. To do this, I recommend something called PD Control. This kind of controller applies more thrust when further away from the object, and less thrust when closer. It also applies thrust to resist the motion of the spacecraft. It's actually very simple:

// Sets the engine thrust and angle based on some target.
void PDControl(Vector position, Vector velocity, Vector target)
    // The current error
    Vector error = target - position;

    // The simple PD control law represented as a 2D vector.
    // KP and KD are arbitrary constants. KP should be positive, 
    // while KD should be negative.
    Vector output = KP * error + KD * velocity;

    // Set the angle and thrust to mirror the output vector
    Engine_Angle = atan2(output.x, output.y);
    Engine_Thrust = output.Length();


PD control will cause your ship to move smoothly toward a target and stop. By tuning KP (the proportional constant) and KD (the damping constant), the movement can be made to oscillate, move quickly, or move slowly. Basically, the PD controller is simulating a spring with friction. The great thing about it is that no matter what physics you throw at the system (say if you add gravity, or collisions with obstacles), the PD controller will still drive the space ship toward the target.


Later edit

var dx = this.x - this.destination.x,
dy = this.y - this.destination.y,
r = Math.atan2(dx, dy) * -1,

// when the speed approaches maxspeed, the acceleration of the ship is just a fraction 
//of its maximum allowed acceleration - assumed to be this.acc
var fractionalAcc = (1 - Math.Pow((this.speed/this.maxSpeed),2)) * this.acc;

this.speed += fractionalAcc;
if(this.speed > this.maxSpeed){ this.speed == this.maxSpeed; }

this.x = Math.sin(r) * this.speed + this.x;
this.y = (Math.cos(r) * this.speed * -1) + this.y;
  • \$\begingroup\$ I thought the question didn't really need much more explanation, but I guess I was wrong, I'll add extra details. \$\endgroup\$ – Johan May 4 '12 at 9:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.