Forum rules - please read before posting.

Is the lerping of acceleration and turning faulty?

In my third-person, point-and-click game, players using nicer computers than I deved on are having the player be very wonky to control, with very slow turning and the feeling of walking on ice. It appears that the way that acceleration and turning are calculated varies based on how fast Update is called, meaning that the faster your computer is, the slower you accelerate. I empirically confirmed this theory by moving the movement code from Char#_Update to Char#_FixedUpdate, and the game then worked perfectly on faster computers.

I speculate that this hasn't been encountered before, because most devs are using more decent computers than I am. The effect is still there for other people, but smaller, because there's less difference between their computers and their players' computers.

To understand the problem, here's the code to set the player's speed from Player#Accelerate (similar code in Char affects turning):





moveSpeed = Mathf.Lerp (moveSpeed, targetSpeed, Time.deltaTime * acceleration);


This runs every Update. This means that you get very different results based on the value of Time.deltaTime. I'll give a couple example calculations (using much slower times than reality and supposing that acceleration is 1 to make calculation easier).

Suppose deltaTime is 1. That means you interpolate all the way, and you reach the target speed in 1 second.

Suppose delta time is .5. That means you get 2 cycles in a second, and the first time you get .5 way to the target speed, and at the end of the 1 second, you're only .75 of the way to the target speed.

Suppose delta time is .25. You get 4 cycles/second. The first time you're .25 of the way, the second you're .4375, third time you're .578, and at the end of the 1 second, you're only .684 of the way to the target speed.

In general, the fraction of how close you get to the target speed in a second is: 1-(1-acceleration*deltaTime)^(1/deltaTime). If you want to see a graph of that, look here (acceleration is 1 for simplicity, x axis is the length of your update in seconds, and y axis is the fraction of the way you get to the targetSpeed in a second.

With a slow computer, you'll reach the target speed in 1 second, and with a fast computer, you'll approach .632 of the target speed in 1 second. This has a pretty significant affect on gameplay.

TL;DR: I suspect lerping with the deltaTime in Update calls is making games not as portable across machines.

Comments

  • edited April 2017
    Ummm, DeltaTime makes things framerate independant. If you read Unity's docs, when you multiply a value by delta time you have to think of it as speed per seconds instead of just speed (ie: 2 meters per second). Delta time allows the game to move the same space no matter what framerate the player has. Deltatime is a tiny amount too, as it's the time spent between frames. Anyway, according to Unity he is using it the right way used, but it's hard to say... I guess one way or another framerate will make it feel faster that way. Though, for moving things precisely in cutscenes using anything other than delta time might be a problem, cause you'll get different lengths in different machines if you do that (potentially ruining a cutscene). 

    By the way, as stated in the docs, Time.DeltaTime will return the fixed framerate Deltatime if you use it in the FixedUpdate loop, so you'll obviously get a different outcome...
  • Thanks for the docs link; I'm actually quite familiar with deltaTime. While it can make things framerate-independent, that's only if used properly; it's not a magic bullet to make anything framerate-independent. As the docs note, "If you add or subtract to a value every frame chances are you should multiply with Time.deltaTime". We're actually doing a more complicated non-linear operation where we lerp towards a value, then replace the previous starting point before lerping again.

    Check my math. I tried to make it clear, but I'm happy to explain further (and if you don't want to wade through the equations, I tried to make the first two examples very concrete).

    And because deltaTime is fixed if used in FixedUpdate, moving to FixedUpdate is an easy way to check if something is actually framerate-independent. Moving it to FixedUpdate essentially guarantees that the code becomes framerate-independent (modulo complications when FixedUpdate can't run fast enough), so if you see different behavior then, the code wasn't originally framerate-independent.

    A simple fix would be to keep an originalMoveSpeed variable, then then swap that into the calculation:
    moveSpeed = Mathf.Lerp (originalMoveSpeed, targetSpeed, Time.deltaTime * acceleration);
  • edited April 2017
    Hey, I'm humbly sorry if my post offended you somehow. I wasn't trying to contradict you or anything. I guess my choice of words was just off (English is not my native language), and I did edit my post a lot (for the same reason). Anyway, I was just thinking out loud, and putting information I know on the table, it's something I do when I'm thinking, all that while I was thinking about deltatime and was trying to imply in the case you present your idea seems to make sense but I'm not sure, hence the "it's hard to say"... there was actually more but I edited stuff and I guess it made the post confusing... and yeah, I say it that way because I haven't been programming all that long, so I don't like to assert my words, that's why you'll hear me say "probably","maybe", or similar words, a lot.

    Anyway, sorry if I offended you in someway, it was not my intention.
  • Oh, no worries, Alverik! I'm definitely not offended, and I'm so sorry if I came off as gruff or condescending or anything. :) I was just trying to make sure I was being clear, and bad on me if I came off as rude.

    Thank you for having taken the time to read through my thoughts at all, I know it takes effort (and I had a bunch of hard-to-read math in there). Cheers, Alverik!
  • Also, my fix code wasn't quite right (the issue stands though), but we can probably fix this to lerp more carefully based on how far you are from the originalMoveSpeed to the targetSpeed. (just moving it all to FixedUpdate is also a sort of fix, but that may be undesirable)
  • It's my understanding that all non-physics related calculations should be performed in Update.  However, I will look into the use of lerping here.  I will let you know if I need more information or testing done.
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Welcome to the official forum for Adventure Creator.