7
\$\begingroup\$

Using delta time with addition and subtraction is easy.

player.speed += 100 * dt

However, multiplication and division complicate things a bit. For example, let's say I want the player to double his speed every second.

player.speed = player.speed * 2 * dt

I can't do this because it'll slow down the player (unless delta time is really high). Division is the same way, except it'll speed things way up.

How can I handle multiplication and division with delta time?

Edit: it looks like my question has confused everyone. I really just wanted to be able to implement deceleration without this horrible mass of code:

else
    if speed > 0 then
        speed = speed - 20 * dt
        if speed < 0 then
            speed = 0
        end
    end
    if speed < 0 then
        speed = speed + 20 * dt
        if speed > 0 then
            speed = 0
        end
    end
end

Because that's way bigger than it needs to be. So far a better solution seems to be:

speed = speed - speed * whatever_number * dt
\$\endgroup\$
5
  • 3
    \$\begingroup\$ What are you trying to accomplish? \$\endgroup\$ Oct 7, 2012 at 15:12
  • \$\begingroup\$ I want to have the player decelerate without having to use a bunch of if statements. \$\endgroup\$
    – tesselode
    Oct 7, 2012 at 15:19
  • \$\begingroup\$ Are you wanting to accelerate and decelerate exponentially every time? You seem somewhat confused about what you're asking since you say you want to double the speed every second, but your code shows doubling the position. \$\endgroup\$
    – House
    Oct 7, 2012 at 17:03
  • \$\begingroup\$ Yeah, I want to change the speed, not the position. Fixed. \$\endgroup\$
    – tesselode
    Oct 7, 2012 at 17:16
  • 2
    \$\begingroup\$ possible duplicate of Friction in 2D game \$\endgroup\$
    – House
    Oct 7, 2012 at 18:27

5 Answers 5

6
\$\begingroup\$

This is where you want to use a little more physics than just modifying the position by some constant value. Give your player a velocity and an acceleration. Then, when you update you can do this:

player.velocity += player.acceleration * dt;
player.x += player.velocity * dt;

Then it's a simple matter of making the acceleration 0 to maintain a constant velocity, or you can make it a positive number to increase velocity or a negative number to decrease velocity.

If you want to "decelerate" just just a negative acceleration, that's all friction is. Friction is just another force like accelerating.

\$\endgroup\$
6
  • \$\begingroup\$ +1 but I was struggling a little bit to answer the sub-question (how to double speed every second) - I can't find a way to exactly double the speed every second, given only delta_time elapsed and current speed! \$\endgroup\$ Oct 7, 2012 at 16:03
  • \$\begingroup\$ You would use an exponential function for the acceleration to double the speed every second. I'm not sure if OP actually wants that. It will get out of hand quickly. \$\endgroup\$
    – House
    Oct 7, 2012 at 16:05
  • \$\begingroup\$ I guess I need to go back to school. \$\endgroup\$ Oct 7, 2012 at 16:06
  • \$\begingroup\$ The OP seemed to be talking about doubling the position every second anyway (player.x = player.x * 2) Which would get out of hand even quicker, exponentially quicker. \$\endgroup\$
    – House
    Oct 7, 2012 at 16:08
  • \$\begingroup\$ He 'wanted' (because I also think he doesn't need that) to double his speed, not position every second, and he wanted to base it on delta_time! I find the problem hard without storing some "oldSpeed" value, refreshed every second. \$\endgroup\$ Oct 7, 2012 at 16:12
5
\$\begingroup\$

As others have noted, the correct formula for deceleration due to dry friction is

velocity += constant * dt * -dir( velocity )

where dir(v) returns a vector of unit length pointing in the same direction as v. (For one-dimensional movement, dir(v) = 1 if v > 0 and dir(v) = -1 if v < 0.) One way to calculate it is as

dir(v) = v / abs(v)

where abs(v) gives the length or magnitude of the vector v.

To keep objects from jittering after they come to a stop (and to avoid dividing by zero if we try to calculate the direction of a prefectly stationary object), we should also ensure that the change in velocity never exceeds the original magnitude of the velocity — that is, friction should never cause an object to start moving backwards. Putting all this together, a reasonable implementation of friction in a game is:

friction = constant * dt;
speed = abs( velocity );
if ( friction < speed ) {
    delta_v = friction * -( velocity / speed );
} else {
    delta_v = -velocity;    // the object stops, or was stopped already
}
velocity += delta_v;

Note that this works even if the object is moving in more than one dimension, so that velocity is a vector. (Of course, the actual code for doing this with vectors might look somewhat different, depending on what notation your language uses for vector arithmetic.)

You can add other velocity changes before or after this code; if you add them before, then small enough forces may be completely canceled by friction, which is actually realistic. In fact, for further realism, you may want to implement static friction by having the constant in the friction calculation vary depending on whether or not the velocity of the object was non-zero at the beginning of this timestep.

Also, if you want to be really accurate, you should take acceleration during the timestep into account when updating the object's position. That is, instead of just doing

velocity += delta_v;
position += velocity * dt;

you should do

velocity += delta_v;
position += ( velocity - delta_v / 2 ) * dt;

where velocity - delta_v / 2 is the average of the velocities before and after adding in delta_v.

This latter approximation to Newton's laws of motion is actually exact as long as acceleration = delta_v / dt is constant, and in any case is a better approximation than the former even for changing delta_v. However, for games with a small and constant timestep dt, the difference is generally not noticeable, at least without side-by-side comparison. The main advantage of the more accurate form is that it makes object trajectories less sensitive to changes in dt.

I should also point out that (dry) friction is not the only force that can slow down moving objects. For example, objects moving through water or air experience drag, which follows a formula that generally looks something like

delta_v = ( a * speed + b ) * -velocity * dt

where a and b are constants that depend on a lot of things such as the density and viscosity of the fluid and the mass, size and shape of the object moving through it. (See the Wikipedia link above for details; a above corresponds to Newton drag, while b corresponds to Stokes drag.)

For macroscopic objects moving through fairly inviscid fluids like water or air, b should be very small or even zero, whereas a viscous fluid like lava or molasses calls for a higher b. For game purposes, just play around with the values until you get the effect you want.

Note that, unlike with dry friction, drag forces never bring a moving object to a complete stop, so we generally don't need to worry about accidental direction reversals. The exception to this is if (a * speed + b) * dt > 1, which can happen if dt is too large or if the object somehow acquires an unusually high velocity; if that might happen, the solution is either to dynamically adjust dt to be smaller for fast-moving objects or to use a higher-order motion integrator (which really goes beyond the scope of this post).

\$\endgroup\$
4
\$\begingroup\$

In these cases you should use exponential functions instead of a normal multiplying. meaning :

player.velocity.x = player.velocity.x * pow(CONSTANT_FACTOR, dt);

It's pretty simple to explain why: when write player.velocity.x += CONSTANT * dt, assuming your game is running @60fps you are adding CONSTANT * 1/60 to velocity 60 times per second, meaning in each second your speed will increase by CONSTANT * 1/60 * 60 = CONSTANT.

Now you want playing velocity to get twice or three times every second, so after one second you'll have new_velocity = old_velocity * CONSTANT you can break this into smaller multiplications and write

new_velocity = old_velocity * CONSTANT ^ (1/60) * CONSTANT ^ (1/60) * ... 
             = old_velocity * CONSTANT ^ (1/60 * 60) 
             = old_velocity * CONSTANT ^  1 = old_velocity * CONSTANT

which means in each frame you need to multiply velocity by CONSTANT^dt

EDIT

Based on the edits the edits you made in your question, you don't really need to implement this exponential method. Assuming you are going to simulate friction, you can also implement more physical method:

Physically friction reduces speed by linear manner, assuming Object mass doesn't change over time. It's applying a force to the object, exactly in opposite direction as object's current velocity. For example let's assume Friction always reduces speed by two units every second, you need to find velocity's current direction, reverse it, and reduce a vector of length two in that direction multiplied dt. here is some code to help you understand:

Velocity_Direction = Velocity / Length(Velocity)
Friction_Power = 2
Friction_Direction = -Velocity_Direction
New_Velocity = Old_Velocity + Friction_Direction * dt

there is one small little thing that you might want to notice, by that code if speed is too low, the Object will jitter in it's position. That's because Fricton_Direction * dt is bigger than velocity itself, which will lead to object moving exactly in opposite direction in the next step, instead of standing still. to fix that you need to add an if statement to check if Velocity is too low and Object should be completely stopped. I'll do it like this:

Friction_Power = 2

if(Length(Velocity) > dt * Friction_Power)
    Velocity_Direction = Velocity / Length(Velocity)
    Friction_Direction = -Velocity_Direction
    New_Velocity = Old_Velocity + Friction_Direction * dt
else
    New_Velocity = Vector(0)

note that Length is a function which gets a vector as an input and returns it's length. for example if your game has a 2d world Length (Velocity) = Sqrt(Sqr(Velocity.x) + Sqr(Velocity.y))

\$\endgroup\$
1
  • \$\begingroup\$ +1, it works! v *= Math.pow ( 2, dt ); to double the speed every second (dt is fraction of a second) \$\endgroup\$ Oct 7, 2012 at 17:43
3
\$\begingroup\$

Without reading more into your question and answering your question as is, this is a simplification of your code:

speed = (speed>0)?MAX(speed - 20 * dt, 0):MIN(speed + 20 * dt, 0)

But as others have stated, to achieve a more realistic (i.e. Newtonian) result, you should implement an "acceleration" variable and update your entity like so:

position = position + velocity * dt + acceleration * dt * dt * 1/2
velocity = velocity + acceleration * dt

Here velocity would be (presumably) your "speed" variable. (If I recall correctly from physics, "speed" is technically ABS(velocity), therefore should be always >= 0)

\$\endgroup\$
1
  • \$\begingroup\$ Very good answer +1 \$\endgroup\$
    – AturSams
    Oct 8, 2012 at 6:50
0
\$\begingroup\$

To make that code shorter, you could do the following:

//define a constant somewhere in your code so you could adjust the value later
DECCELLARATION_RATE = 20;
//Checks if the speed is positive or negative so we will decrease it's absolute value:
sign = (speed >= 0? 1 : -1);
//Decrease the absolute value of the speed while maintaing it's sign
speed -= sign * DECCELLARATION_RATE * dt
//If the object is moving too slowly, the above command will change the speed's sign and with it the direction of the movement. 
//What we want to do is stop the object in this case.
if(sign != (speed >= 0? 1 : -1)) speed = 0;

The operator (condition ? value_if_true : value_if_false ) is called the ternary operator. You can read about it more here:

http://en.wikipedia.org/wiki/Ternary_conditional_operation

\$\endgroup\$
5
  • \$\begingroup\$ 1. you answer only works for 1D world. 2. in case we assume OP wanted 1D answer both me and Byte have already given this answer. \$\endgroup\$
    – Ali1S232
    Oct 7, 2012 at 19:23
  • 3
    \$\begingroup\$ The link you gave is goes to the generic page about question marks. Why is your answer spending more space explaining ternary operators with absolutely no explanation of your movement code? \$\endgroup\$ Oct 7, 2012 at 19:33
  • \$\begingroup\$ @JustinSkiles Thanks, I fixed the link. He asked how to make his code short and simple, I offered a tool called a ternary operator. I'm guessing the OP is not familiar with it so I explained what it does in detail. I edited the answer to add some comments explaining the code itself. I thought it was very short and pretty clear once your know what a ternary operator does. \$\endgroup\$
    – AturSams
    Oct 7, 2012 at 19:42
  • \$\begingroup\$ @Gajoo All the things you wrote do not change the fact that 1.this answer is suitable for manipulating the x-axis speed in a 2D platformer game. 2. It matches the edited question perfectly. 3. You most likely downvoted Byte56 originally and myself now because of being competative. None of your explainations show why this answer is less useful when considering the question. In addition the last part of your answer deals with the exact same suituation. So you must think it's somewhat useful. \$\endgroup\$
    – AturSams
    Oct 7, 2012 at 20:32
  • 3
    \$\begingroup\$ +1 it may be not the best answer, but it shows the solution in a different way, and therefore is a positive input not deserving -3 for sure. \$\endgroup\$ Oct 7, 2012 at 21:08

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .