Velocity and deltatime confusion

Started by
8 comments, last by Finalspace 8 years, 8 months ago

So I have a minor question.

Lets say I have a player moving at a velocity of 600 units. They hit some object like a puddle. When they hit this puddle I want to reduce their velocity by half. So I do:

 
velocity -= velocity * 0.5f;
 

But where does the deltatime come in?

If I multiply by deltatime (0.0166666667f), I don't think I'll be reducing my velocity by half.

So what's the correct way to do this? Should deltatime only be used when the update is constant?

Advertisement
deltaTime should be used when the change in velocity is a force. If it's a one-time instantaneous change, then you can do it like you've written there.

So the question is: The next frame, if the player is still in the water, are you going to halve their velocity again? (If so, use a force) Or do you only halve their velocity when they first enter the water? (If so, do what you're doing now)

The old formula "distance = velocity * time" is where your delta time comes in. I.e. when you update the player position.

You're missing time and frame from your thoughts.

See why:

Lets say I have a player moving at a velocity of 600 units.

You're moving at 600 units per what? Per second? Per minute? Per hour?
Normally we assume it's per second.
If we're simulating at 16.67ms per frame, then the object is moving at 10 units per frame.

Likewise, if the deacceleration is instantaneous, then you just divide the velocity by 2. Because it happens in that frame. Think in frames. Because you're dividing time (which is contiguous) into discrete frames.

Now if instead, hitting the poodle deaccelerates the object over a second, then you need subtract half of the velocity during 60 frames over and over again and multiply it by delta time (16.67ms). Because 60 times 0.016666667 is 1.

Think in time and frames.

deltaTime should be used when the change in velocity is a force. If it's a one-time instantaneous change, then you can do it like you've written there.

So the question is: The next frame, if the player is still in the water, are you going to halve their velocity again? (If so, use a force) Or do you only halve their velocity when they first enter the water? (If so, do what you're doing now)

In this case it would be a one time deal. If the player hits the object, half their current velocity.

You're moving at 600 units per what? Per second? Per minute? Per hour?

Normally we assume it's per second.
If we're simulating at 16.67ms per frame, then the object is moving at 10 units per frame.

Likewise, if the deacceleration is instantaneous, then you just divide the velocity by 2. Because it happens in that frame. Think in frames. Because you're dividing time (which is contiguous) into discrete frames.

Now if instead, hitting the poodle deaccelerates the object over a second, then you need subtract half of the velocity during 60 frames over and over again and multiply it by delta time (16.67ms). Because 60 times 0.016666667 is 1.

Think in time and frames.

I was thinking in terms of I'm just moving at a rate of 600 units or that is my current velocity.

But either way in the case I was talking about it would be all in the one frame so it would just be:


velocity -= velocity * 0.5f;

Now in the case where I hit the poodle ;)

And the poodle makes me slow down my velocity over the time I'm colliding with them by half (or over a 60 frames assuming we are stimulating 16.67ms )

Then if I am correct my equation should be:


 
if(player.collides(poodle))
    player.velocity -= player.velocity * 0.5f * deltatime;
 

If you're wanting to do a cheap simulation of drag then it should be applied as a force in the opposite direction of velocity and scaled by velocity.


float dragFactor = 0.5f;
vec drag = velocity * -dragFactor;
vec netForce = velocity + drag;
position += netForce * dt;

Note that realistic drag physics is a little more involved, but still generates a force to be added to the net force on the entity. In this case 0.5 is a bit steep. It's going to bring you to a screeching halt.

Incidentally, v -= v * 0.5 is equivalent to v *= 0.5.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

I was thinking in terms of I'm just moving at a rate of 600 units or that is my current velocity.

Even in pure Physics terms, velocity is expressed as an expression of time. e.g. meters / seconds; miles / hour; kilometers / hour.

But either way in the case I was talking about it would be all in the one frame so it would just be:

velocity -= velocity * 0.5f;

If it is just one frame, then yes; that's the correct way of doing it.

Now in the case where I hit the poodle ;)
And the poodle makes me slow down my velocity over the time I'm colliding with them by half (or over a 60 frames assuming we are stimulating 16.67ms )
Then if I am correct my equation should be:

 
if(player.collides(poodle))
    player.velocity -= player.velocity * 0.5f * deltatime;
 

Yes. You would have to have a way to ensure that "if(player.collides(poodle))" returns true for 60 frames. One way to ensure that is to run a routine that schedules itself to run for 60 frames; and this routine all it does is to decrease the player's velocity.

For example:
 
if(player.collides(poodle))
    routineSystem.runRoutine( &decreasePlayerVelocity, player, 1.0f ); //Run the routine for one second

//Define the routine.
bool decreasePlayerVelocity( player )
{
    player.velocity -= player.velocity * 0.5f * deltatime;
    return true; //If we return false, then the routine was cancelled prematurely.
}
Having such generic system that schedules and runs arbitrary routines for a fixed amount of time is very useful in games. RPG games are a prime example: "Heal the player over the course of 5 seconds", "Poison an enemy for 20 seconds".
Once the routine is over (i.e. player died) or the time expires, the routine is de-scheduled.
This way you don't have to worry about ensuring player.collides(poodle) is true for 60 frames.

Then if I am correct my equation should be:

if(player.collides(poodle))
player.velocity -= player.velocity * 0.5f * deltatime;

This will only work if "player.velocity" is constant for the entire duration of the slowdown. Eg save the current velocity when the player first touches the puddle and use that. Otherwise all but the first frame will use smaller and smaller values for player velocity, getting you less than 0.5x slowdown over 1 second (and how much less would be framerate dependent!)

(assuming you were intending to call this every frame, not once at the start with dt=1 second)

o3o

Everything that happens in a game is just a manipulation of numbers by code at varying points of time.

Using that logic we can point out that velocity is only a useful metric when you combine it with time, if something is moving at 300 velocity then that velocity has to be compared to a time, perhaps it is pixels per second.

So if we just used exactly a second of time and our game is updating, now it moves the object 300 units, if we instead had 0.5 seconds pass then our velocity is still the same, we simply only -move- 150 units because the entire timeframe of a step never passed.

If you hit an object and it halves your velocity then the details become important. To be simulation correct you want to make sure you simulate the effects over the entire length of time, using our earlier example if we just simulated a second and halfway through your object hit another object that halves its velocity, then you have to compensate for where the object would be(it wouldn't have moved 300 units.)

If we talk about simulating an arbitrary movement over time with the velocity changing with time as well, then you're moving into calculus territory.

Its easier to think in a way how integration works.

We use the acceleration - which is defined in m/s² to integrate into velocity.

We use velocity - which is defined as m/s to integrate into position.

Position is just a distance (m) from the origin.

Therefore if we look at one frame in our game (typical 1/60 of a second) then we need to integrate our "delta-time" which is normally 1.0 / 60.0 into all the integration equations - otherwise your acceleration, velocity and position is getting 60 times faster than it should be.

When you do collision detection, the velocity is already integrated so that it contains only the acceleration for one frame - so you dont have to put the delta time again.

- Integrate with delta time

vel += acc * dt;

pos += vel * dt;

- Solve collisions without delta time:

vel += -(1.0 + restitution) * relative velocity along normal * normal

The only way you need delta time again is when you want to use the distance in velocity - then you need to divide it by the delta time - to convert it into m/s.

This topic is closed to new replies.

Advertisement