Trouble getting framerate independency with Time.deltaTime

Hi all,
I’m having some problems when using the conventional method of making movement framerate independent. I’m using Time.deltaTime in Update() to compensate for slower framerate when adding or subtracting movement related values, but there seems to be something wrong with my code which makes my character jump in different y speed even though I’m multiplying the gravity with Time.deltaTime.

The code below is reduced to its core functionality. When the jump reaches apex the y value of the characters position varies quite a lot when the framerate is fluctuating.

void Update () {
		
		
		isGrounded = controller_.isGrounded;
	
		isJump = inputController_.GetIsJumping();
		if(isJump && isGrounded) {
			reachedApex = false;
			verticalSpeed_.y = junpStrength;
		}
		else if(!isGrounded) {
			if(verticalSpeed_.y < 0f && !reachedApex) {
				reachedApex = true;
				Debug.Log(transform.position.y); // Big differences in this value
			}
			verticalSpeed_.y -= gravity*Time.deltaTime;
		}
		else if(isGrounded) {
			verticalSpeed_.y = -gravity*Time.deltaTime;
		}
		CollisionFlags flags = controller_.Move(verticalSpeed_ * Time.deltaTime);
	}

Have I gotten this method all wrong or what?
Any thoughts would be much appreciated.

Thanks!

Your problem here is that you're using the timeDelta to modify the speed based on gravity once per frame, and then you (correctly) use timeDelta to modify the position based on the speed. With this setup, you don't take the changes in speed that happen between two frames into account. I suggest either brushing up on your calculus (unfortunately mine is too rusty as well), or doing these calculations in FixedUpdate() instead, based on fixedDeltaTime.

–

Hey Philipp, thanks for answering. Maybe this is a stupid question but, I'm not exactly sure what you mean with "changes in speed that happen between two frames"? Update() runs every frame, so I don't understand how verticalSpeed_.y can change between frames?

–

![MichealJacksonPopcorn.gif][1] [1]: http://i.imgur.com/KHQfR.gif

–

That's not correct Philipp, the error you describe is microscopic and irrelevant here. You do exactly what Chu describes as a matter of course in vid. games. (Indeed PhysX works like that.)

–

The error is small, but cumulative. Here's a physics tutorial that describes Chu's calculation and in what kinds of errors it can result (with a numerical example): [http://gafferongames.com/game-physics/integration-basics/][1] Physics engines generally use fixed time steps to not do the extra work required to account for this, which is why I suggested using fixedUpdate in the first place. [1]: http://gafferongames.com/game-physics/integration-basics/

–

3 Answers

3

This might not be entirely applicable, but you are applying gravity in a wrong way!

As stated here (read it if you want an explanation)

You need to apply gravity half before and half after, otherwise jumping will vary with framerate. (especially low ones)

So instead of doing:

velocity -= Vector3(0, gravity, 0)*Time.deltaTime;
characterController.Move(velocity*Time.deltaTime);

You need to do:

velocity -= Vector3(0, gravity/2*Time.deltaTime, 0);
characterController.Move(velocity*Time.deltaTime);
velocity -= Vector3(0, gravity/2*Time.deltaTime, 0);

Hope this helps, if not I can just delete this answer :slight_smile:
Benproductions1

Hi Ben, interesting thought. Unfortunately it's not doing the trick for me. Thanks though!

–

Whoa didnt know that and i was veerry disapointed cause i thought that delta time didnt work correct in unity :( I give all my hopes to this... please let it work for me :/

–

It seems essentially inconceivable that DeltaTime would not work in a game engine.

–

Of course it works. It's just the time since the last frame, nothing more and nothing less. If anything "doesn't work" then you did it wrong.

–

HELL YEAH GOT IT WORKINGGGG !!!!! IT REALLY WORKED AND I WAS SOO DEPRESSED , I was almost ready to give up my entire game !!! Meaning to give up almost 2 years of solo work but heall yeah got it working !!! THNX man very very usefull information !!!

–

You have asked (I believe),

how to use .Move rather than setting the position.

To set the position:

transform.position.y =
StartingVelocity * (Time.time - _startTime)
- 0.5 * 9.8 * (Time.time - _startTime) * (Time.time - _startTime);

To use .Move:

newYValue = // same as above
.Move( Vector3(0, newYValue-transform.position.y, 0 ) );

NB, one of your control structures appears to be incorrect:

else if(!isGrounded) {...}
else if(isGrounded) {...}

Regarding your arithmetic as presented:

[8894-threelinebounce.zip|8894]


To animate the usual way:

transform.position.y =
StartingVelocity * (Time.time - _startTime)
- 0.5 * 9.8 * (Time.time - _startTime) * (Time.time - _startTime);

[8931-twodemos.zip|8931]

Note - try as Update, FixedUpdate, there is no difference.


Next, I wrote a run loop that happens at random times: “harsh demo”

You will see that it makes no difference.

Both projects are included in the previous link.


“having a hard time grasping the formula you just provided” x = x0 + v0 t + 1/2 g t2

eg explaination

Just a reminder that this controls structure else if(!isGrounded) {...} else if(isGrounded) {...} is wrong, encourage you to seek advice from others on it. Perhaps that's additionally causing you troubles?

–

I used EXACTLY the max # of characters in that comment :-)

–

Ok, thanks Fattie!

–

You say “when the framerate is fluctuating” and “big difference” - these are pretty subjective. What numbers are you seeing, and what do you expect?

Your code is correct, but if you’re getting huge variations in framerate it’s quite possible for one frame to take so long to process that you miss part of the jump’s apex. For instance you could skip from +1u/s to -1u/s, completely missing the 0u/s speed, and ending up with your apex marked at the point where you had +/-1u/s (a lower point). There’s no reason for you to code around this in a video game (though it’s possible) - you want to get rid of the fluctuation instead.

You’ve probably already done this, but it’s a good idea to also go through your script and double-check that nothing else is modifying your vertical speed value. :slight_smile:

Your code above is absolutely right, it's pretty much the same thing I've written twenty times by now in my own little projects. It seems like moving things to FixedUpdate has helped you out, so now I have even less idea why it wasn't working. Were you calling Update yourself, or did you change the project settings to ... I don't even know. Your code is right, there's just something funky in your setup. :(

–

Ah well... :)

–

How does it work if you do a build and run standalone? I have some things like this that simply don't work really smoothly in the editor, while running fine standalone, regardless of framerate.

–