DEV Community

Yunus Emre Güzel
Yunus Emre Güzel

Posted on Originally published at blog.emreguzel.ca

Update vs FixedUpdate in Unity: Where Movement and Timers Go

When I built my 3D maze game in Unity, two things had to happen every frame: a ball rolls around when you press the arrow keys, and a timer counts down from 65 seconds. Unity gives you two places to put code like that, Update() and FixedUpdate(), and putting it in the wrong one causes some confusing bugs. The ball moves faster on a powerful PC than on a laptop, it feels jittery, or the timer runs at the wrong speed. Here is where each piece goes and why.

The Problem: Movement That Depends on the Computer

A common first attempt is to push the ball inside Update():

void Update()
{
    float horizontal = Input.GetAxis("Horizontal");
    float vertical = Input.GetAxis("Vertical");
    rb.AddForce(new Vector3(horizontal, 0, vertical) * 5f);
}
Enter fullscreen mode Exit fullscreen mode

It works on your machine, so it looks fine. But Update() runs once per frame. A computer running the game at 144 frames per second pushes the ball 144 times a second, and one at 30 frames per second only pushes it 30 times. Same key, very different speed.

Update() vs FixedUpdate(): What’s the Difference?

  • Update() runs once every frame. How often depends on how fast the computer is. Use it for things tied to what you see: timers, UI text, and checking one-time key presses.

  • FixedUpdate() runs on Unity’s physics clock, by default 50 times a second on every computer. Use it for anything that works with a Rigidbody: forces, velocity and physics movement.

The Fix Part 1: Ball Movement in FixedUpdate()

This is the movement code from my maze game. Because it’s in FixedUpdate(), the ball gets the same push the same number of times per second on any computer:

void FixedUpdate()
{
    // All physics code should be in FixedUpdate
    if (gameStart && !gameOver)
    {
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");
        Vector3 force = new Vector3(horizontal, 0, vertical);
        rb.AddForce(force * 5f);
    }
    else
    {
        // Stop the ball when the game is over
        rb.velocity = Vector3.zero;
        rb.angularVelocity = Vector3.zero;
    }
}
Enter fullscreen mode Exit fullscreen mode

Reading Input.GetAxis() here is fine, because it’s a value you hold: it stays the same between physics steps.

The Fix Part 2: The Timer in Update() with Time.deltaTime

The countdown timer isn’t physics, it’s something the player watches, so it belongs in Update(). The trick is Time.deltaTime, the number of seconds since the last frame. Subtracting it every frame makes the timer count real seconds no matter how many frames per second the game runs at:

void Update()
{
    if (gameStart && !gameOver)
    {
        timeCounter -= Time.deltaTime;
        time.text = " " + Mathf.Round(timeCounter).ToString();

        if (timeCounter <= 0f)
        {
            gameOver = true;
            result.text = "Game Over";
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Without Time.deltaTime, writing timeCounter -= 1; would knock off one second per frame, so a 65-second timer would be over in about one second.

Two Traps to Avoid

  • One-time key presses in FixedUpdate(): Input.GetKeyDown() is only true for the single frame you press the key. FixedUpdate doesn’t run every frame, so it can miss that press, and your jump “sometimes doesn’t work”. Read it in Update(), save it in a variable, and use it in FixedUpdate().

  • Unity 6 renamed velocity: rb.velocity is now rb.linearVelocity. Older tutorials, mine included, show a warning there. Swap the name and it works the same.

Quick Rule of Thumb

If it touches a Rigidbody, put it in FixedUpdate(). If it’s a timer, UI, or a button press, put it in Update() and use Time.deltaTime for anything measured in seconds. Collisions, like losing a life when the ball hits a wall, go in OnCollisionEnter(), which Unity calls for you.

You can see all of this working together in my step-by-step 3D maze game tutorial, which includes the scene setup, the UI and the complete script. New to Unity? Start with installing Unity the right way.


Originally published on my blog. I post new C, Python and AI-agent guides there regularly.

Top comments (0)