Having an hard time with DeltaTime

Premise

I’m using a custom MovementComponent which derives from UPawnMovementComponent. From what I noticed, differently from a UCharacterMovementComponent, it does not include any time-step handling.

I handle all movement logic (e.g., walking, jumping, falling, etc.) with a Finite State Machine I implemented; each state (GroundedState, JumpingState, FallingState, etc.) has its own Enter, Execute and Exit methods.

What I do in these state methods is just modifying MovementComponent->Velocity (for example, based on the Input, or applying my gravity when falling). I don’t use DeltaTime in any way inside of these methods.

Then, in the TickComponent method of my MovementComponent, I just update the FSM and call the Execute method of the relevant state the Pawn is in. This gets the Velocity modified by the state methods as said before.

Still in the TickComponent method, I do:

FVector Delta = Velocity * DeltaTime;

SafeMoveUpdatedComponent(Delta, SomeRotation, true, Hit);

…and the Pawn moves/jumps/falls accordingly.

The Problem

With changing framerates, I get different results on different machines. For example, let’s take the Falling state. In the Execute method of Falling state, I just do:

MoveComp->Velocity.Z -= 25.F;

I see the character falling with some speed at 60FPS. I see the same character with the same code falling differently at 30FPS, 10FPS, and so on.

I know why it’s happening, and I get I have to implement some kind of time-step management. I delved into the UcharacterMovementComponent and saw that movement methods such as Phys_Walking do use deltaTime and Iterations, but I wasn’t able to reproduce this kind of time-step handling in my own scenario.

I’ve read several articles and blog posts about fixing the time-step (one above all: http://gafferongames.com/game-physics/fix-your-timestep/).

The Question

Let’s say I want to implement the Semi-Fixed solution proposed in that link above; how should ago about it?

  1. can I use the DeltaTime that get passed in the TickComponent function? Or should I calculate my own as per that article?

  2. is my overall implementation fine at all? (I mean, having different FSM states just modifying Velocity, and then just multiplying it by DeltaTime?)

  3. where exactly should I implement the Semi-Fixed stuff? Is the TickComponent the right place to do that? Or should I do that in the FSM states?

Thanks!

MoveComp->Velocity.Z -= 25.F * DeltaTime;

you might have to adjust that 25.F to get the right fall acceleration.

That seems odd that you are having this behavior when multiplying by deltatime. That’s the exact problem it’s supposed to prevent from happening.

I’m having a little trouble picturing what’s going on. I did notice you posted this line :

MoveComp->Velocity.Z -= 25.F;

This is not scaled against delta time. Are you scaling it elsewhere later?

the delta value scaled with DeltaTime turn in to change per secound

Yes. That line of code is from the Falling state, where I subtract a value (in this case 25) to the Z component of the Velocity. Then in the TickComponent function all the Velocity vector is always scaled by DeltaTime…

That line of code is from the Falling state class; should I multiply by DeltaTime there (only the Z component of Velocity) and then multiply by DeltaTime AGAIN the whole Velocity vector in the TickComponent function, per tick?

Anything that you think should be binded to time insted of frames. Tick is executed on every frame, DeltaTime is estiumated time difference between frames, by scaling it change of value by it it will change as much as it would do over that estimated that time. Whatever you like that it’s you to decide, but practically all positional changes should be scaled by deltatime, otherwise they become fps dependent.

Well, as I said, all “changes” are made changing MovementComponent->Velocity. Then in the TickFunction Velocity is multiplied by DeltaTime. Shouldn’t be it framerate independent? There’s something really wrong here…

if you want to know why that gravity get multiplied times DeltaTime twice, it’s because acceleration is proportional to the square of time, whereas velocity is proportional to time (not squared). So Velocity = Speed x Time; Acceleration = gravity x Time x Time. Each “Time” represents a delta time.

MoveComp->Velocity.Z -= 25.f * DeltaTime; // first gravity delta correction

Delta = Velocity * DeltaTime; // 2nd gravity delta correction, 1st velocity delta correction

That’s fine, I just wanted to know if it won’t cause any problem (multiplying twice…). But, the question stays the same: do I need any kind of time-step management (as they do in the UCharacterMovementComponent)?

Just tried multiplying Velocity.Z by DeltaTime as well, and at 120, 60, 30 and even 10 FPS, it ALMOST moves by the same amount (there is still a difference, but it’s hardly noticeable). At 5 or 2 FPS it moves way more than at higher FPS…looks like it jumps higher at lower FPS.

So, would any of those implementations (Semi-Fixed, Fixed, etc.) help with this?

Let me rephrase what I actually need: I want that, independently of FPS, my Pawn jumps/falls/moves by the same exact distance. I thought that DeltaTime was for this, but either I was wrong or I do something wrong in my code, because at different FPS, the Pawn jumps/falls/moves by different amounts.

As I stated earlier, in the UCharacterMovementComponent I see some kind of time-step implementation (with iterations, etc.). Do I need to do something like that? Would it help with what I want to achieve?

I don’t know your exact game/app so I can’t say with absolute certainty, but in general, No, you should not need to add any time stepping of your own. If you have physics objects that move very fast and interact with one another, then it might be necessary to add iterations to resolve all interactions properly. The character movement component is built the way it is so it can handle anything users throw at it for all games and all scenarios. If you’re writing game specific code, you can have more streamlined code.

Acceleration = gravity x time x time is an approximation. The actual physics formulas are more complex, but for most cases, it works fine and it’s fast easy code. You might see a difference depending on more extreme speeds and/or frame rates.

The character movement component does it for networking reasons (rendering can run at 60fps, but the network updates might only be coming at 20fps). If you’re not a networked game, this is not necessarily the route to take - visually, the client’s motion curve can/will be affected but it’s done to keep clients and servers in sync and physics/interactions consistent.

You’re seeing a different motion curve at 30fps vs 2fps. That’s normal. You can either correct the motion curves OR velocities, but not both. If you use Fixed time-stepping, for instance, you’ll get consistent motion curves, but velocities will be screwed up – if you time your jump, you’ll notice it takes the character much longer from beginning to end at 2fps than at 30fps using fixed time steps. If you use DeltaTime, all the timings will be accurate, but you’ll see the motion curves affected.

Here’s an illustration. In low frame rate and trying to preserve velocities, you don’t see the top of the curve because it happens in-between frames.

Now if you fix the frame steps, you’ll see the whole curve but from beginning to end it’ll take longer.

I don’t know what application you’re building so I don’t know your priorities. If you don’t care about frame rate and you want accurate motion curves, then fixed step is the solution. If you care about keeping the game running at consistent rate, then you use DeltaTime.

I don’t really see a use for Semi-Fixed because inconsistent velocities is such a different experience than inconsistent time that switching between them would be quite jarring. You can use DeltaTime at fps > 30 and fixed steps at fps < 30 but it would feel weird in a game.

Wow, thank you very much! This is the explanation I was looking for. My game doesn’t have networking stuff, neither I need physically accurate simulations, so I guess I’ll just go with DeltaTime. Thank you for taking the time to explain all this.

Numerical Integration

You must always multiply by deltatime when updating a variable during simulation. When you update velocity, you are doing a numerical integration of the acceleration: dv = a * dt. If you don’t put the deltatime, it means that the deltatime is implicitly 1 second: dv = a * 1, which is totally wrong.

position(n) = position(n-1) + velocity(n-1) * dt

velocity(n) = velocity(n-1) + a * dt

here is a better explanation of numerical integration: Integration Basics | Gaffer On Games

Timestepping

As you can see if you study the theory of numerical integration, the integration result depends on the integration deltatime of your simulation. When you run at low frame rates you’ll experience a change in your animation timings. Speeds and position curves will change expecially at very low rates. You can fix this using a fixed timestep algorithm (http://gafferongames.com/game-physics/fix-your-timestep/). Looking at the graph above, we have the same altitude for frame n and n+1, it seems that the speed is zero. Actually this depends on having correct smooth curves for position and speed but sampling the position at large time intervals. It’s a well known phenomenon called Aliasing (Aliasing - Wikipedia).
The fact that when you use fixed timestep you get slower animation, as rantrod says, is true only if don’t split your physics update in sub-updates at each frame. If at each frame you use a fixed, hardcoded deltatime, of course you get always the same curves but the animation time changes depending on the ratio between the real deltatime and the hardcoded deltatime. If, instead, you implement correctly the fixed timestep algorithm, then you will get correct results. As always, Gaffer on games is the best reference.