Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

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;

share|improve this question
3  
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. –  Sam Hocevar May 4 '12 at 11:54
    
No shit... So in my attempt to make things more realistic I'm actualy making it less realistic? FML... –  Johan May 4 '12 at 12:00
    
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. –  joltmode May 4 '12 at 12:12
    
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. –  Sam Hocevar May 4 '12 at 12:44
    
Thanks @SamHocevar , I've tried getting rid of the -1 before but without success... Thanks :) –  Johan May 4 '12 at 12:59
show 3 more comments

3 Answers

up vote 7 down vote accepted

You have an opposing force called "friction", which is proportional to speed. This is how objects falling in an atmosphere are modelled, 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

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

share|improve this answer
    
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 –  Johan May 4 '12 at 11:36
    
@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. –  Gustavo Maciel May 4 '12 at 11:38
    
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 –  Johan May 4 '12 at 11:50
    
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. –  joltmode May 4 '12 at 11:55
1  
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. –  joltmode May 4 '12 at 12:02
add comment

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.

share|improve this answer
    
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! –  Johan May 4 '12 at 11:33
    
@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. –  Sam Hocevar May 4 '12 at 11:44
    
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) –  Johan May 4 '12 at 11:48
    
@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. –  teodron May 4 '12 at 11:50
    
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. –  teodron May 4 '12 at 11:51
show 1 more comment

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;
share|improve this answer
    
I thought the question didn't really need much more explanation, but I guess I was wrong, I'll add extra details. –  Johan May 4 '12 at 9:52
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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