Backstory
So I encountered a pretty horrible bug that occurred on release day for my last game–one that stops players from being able to play the game at all. What’s worse, I couldn’t even test the bug on my own machine, since it was kind of hardware-specific. After doing a ton of research, I couldn’t find any solutions online or anywhere, which is why I’m making this post now, for future reference in case anyone has the same issue. Furthermore, this post hopes to prevent this “bug” from happening in Unity games from now on.
The Problem
So the bug was actually pretty specific. When the framerate of my game was over ~150 FPS, the player character just refused to move. I phoned a friend to test the issue and confirmed that the framerate was what was causing the bug. I checked everything I could think of, thinking that maybe it was related to the Time.deltaTime variable. But none of my code changes helped.
Previous Solutions
At the time, I figured it was an issue with floating point precision. After all, with higher framerates, the Time.deltaTime variable shrinks down to a really small number. Maybe it was so low that the deltaTime variable was just coming in as 0. So I wrote and re-wrote code until everything was based on reading the inputs directly without additions and it still didn’t solve anything.
So my temporary solution was to just cap the framerate at 120FPS.
The Real Solution
So I finally ran some more tests yesterday and found that the issue was not with any of the code, but with the Character Controller itself. I ran a test scene at 500FPS and printed a log of the variables that fed into the Controller.Move() function and found that they were NOT 0. There was enough precision for Time.deltaTime (Which factored into the variable) to not be 0. More specifically, the Move() function was reading the player input and multiplying it by the Time.deltaTime. So if the Move() function wasn’t receiving a 0 vector, why would it refuse to move?
That’s when I found this little option right here:
It’s something I didn’t even think to consider, but this variable was the only thing standing in the way from fixing this bug I must’ve spent over 15 hours on. To reiterate, when the Move() function received a really low value due to high framerates and the deltaTime variable being so low, the character refused to move because the Minimum Move Distance on the Character Controller was higher than the input variable. So obviously, once I lowered the Minimum Move Distance to 1e-06, the issue was resolved.
Note that this only came up because my Motor code was in Update. (Actually, I’m using the old default Character Motor, which has an option for “Use Fixed Update” which I had turned off.) If your movement code is in FixedUpdate, I would assume you would multiply by the FixedDeltaTime instead, which normally never results in a variable lower than 0.001.
Thoughts
These kinds of bugs are scary, because this option was so obscure and I wouldn’t have even noticed a problem because I normally couldn’t run my game at a framerate that high. It makes me think that there might be other theoretical issues when framerates get even higher. Are there other things with a “minimum” setting that could break on higher framerates?
And the worst part is that my solution only delays the problem until the framerates get even higher. What if framerates get so high that the Move() input becomes less than 1e-06?! For future proofing especially, on future hardware we’ll be able to run games a lot faster than we can now. If there’s no Framecap option or VSync in a game, something that used to work would start to break 10 years from now. Sure, we can just keep lowering the Minimum Distance on and on, but how far is enough?
Anyways, I hope this helps you in making your games. If anyone else encounters this issue, this post should serve as a reference and guide for what to do. Good luck!
