A common issue that can plague Unity devs, especially beginners is that input doesn’t always work consistently. The most obvious manifestation of this is when your jump button doesn’t always cause your player to jump, or your shoot button doesn’t always shoot!
While these symptoms can be caused by a number of things, there is a common mistake that is the cause in a large number of cases, and it’s easy to fix!
The problem that causes this most often is checking input inside the FixedUpdate() method instead of the Update() method. Move all your input code to the Update() loop (either in the Update() method itself or a method that is called during the Update() loop), and you will fix any issues caused by checking input in FixedUpdate().
Why You Must Check Input in Update()
The difference between Update() and FixedUpdate() is too technical to include in this post, but these two facts are all you need to know right now:
- Update() and FixedUpdate() run on different schedules
- Unity checks the input state on the Update() schedule, NOT the FixedUpdate() schedule.
When you ask Unity to tell you if the player has pressed the Jump button down, e.g.:
You are asking Unity “is the current state of the Jump key ‘pressed down this frame’?”. Since the state is refreshed during Update(), you must check the state in Update(). If you were to check in FixedUpdate() you won’t always get the current result.
Let’s say you are playing your game at 100fps (frames per second). This framerate is how often Unity will call the Update() method, and therefore how quickly the input (and other things) are refreshed by Unity. FixedUpdate(), however, will run at 50fps. FixedUpdate() is for physics, and will always run at the same rate, whereas Update() will fluctuate.
In our hypothetical game, Update() is running twice per every FixedUpdate(), so you can represent this like:
And so on.
Now keep in mind that Unity refreshes input in Update(), and see what happens when you check input in FixedUpdate():
- Update() – player presses jump (Input.GetKeyDown(“Jump”) is now true
- Update() – input is refreshed – player did not press jump in this frame – (Input.GetKeyDown(“Jump”) is now false
- FixedUpdate() – Input.GetKeyDown(“Jump”) is false – the jump was missed!
Update and FixedUpdate
The above example is simplified to demonstrate the point. In reality, Update() can be slower than FixedUpdate(), and can even fluctuate so much that sometimes it is faster and sometimes slower. If Update() runs less frequently than FixedUpdate(), you will still have input issues if you check the input in FixedUpdate(), but it will manifest as delays in input rather than missed inputs. But in ALL cases, you need to check input in Update() to ensure you are in sync with Unity’s input updates.
Because this error causes inconsistent problems, and is quite reliant on framerate, it is one of those things that can often not become obvious until you test on different devices, or may only happen in certain parts of your game where the framerate varies. So
Physics Movement and FixedUpdate()
If you have input code in FixedUpdate(), it may be because you are using physics for your movement. You obviously tend to have your input code and your movement code together, so what do you do when you need to do physics movement in FixedUpdate() and input in Update()? There are many things you can do, but the simplest is to simply store what you need from the input in Update(), then act upon it in FixedUpdate().