Home > Mobile >  How to handle FixedUpdate() and Input in Unity?
How to handle FixedUpdate() and Input in Unity?

Time:03-07

As far as I know, in Unity, physics related things should be done in FixedUpdate() method. And FixedUpdate() is called at fix timestamp and Update() is not. Let's asuume I have a gameobject with RigidBody2D component attached and get the user input in Update(). User can move the object with left and right arrow. See the fllowing figure, user input happen at frame 2 and 3 and FixedUpdate() is not called. During frame 2 user pressed right arrow and say it move the object 1 unit and object is currently located at (0, 0). The object position should be now at (1, 0). But nothing happen because FixedUpdate() wasn't called. And again in frame 3 FixedUpdate() is not called and user press the left arrow. So, it move the object 1 unit left and now the position is (0, 0). When we reached frame 4 FixedUpdate() is called and if I put the input data in a variable at previous frame, frame 3, current object position will be (0, 0). So, in this scenario our gameobject never reached the position (1, 0) but it's supposed to be. Probably it's not the only problem. There might exist many scenario like called FixedUpdate() 2 times within one frame and called FixedUpdate() only every 3 or 4 frames and so on. So, should I ignore such case because I think it's not too obivious to user. If I shouldn't, how can I handle it? Do I need to queue all the input data and do all the movement when the FixedUpdate() is called? What I tested is store movement data in a variable and if movement occurred then put true to a flag. If the flag is true the object will be moved inside FixedUpdate(). But the problem is it can handle only one input. If FixedUpdate() is not called the next movement will never be happen.

Figure

void FixedUpdate()
{
  if(moved)
  {
    Vector2 movePos = rb2d.position   new Vector2(x, 0);
    rb2d.MovePosition(movePos);
    moved = false;
  }
}

void Update()
{
  if(!moved)
  {
    x = Input.GetAxisRaw("Horizontal");
    if (x != 0) moved = true;
  }
}

CodePudding user response:

FixedUpdate isn't guaranteed to run on a fixed schedule because Unity is designed to deal with lag. Instead, whenever Update is called, Unity checks if any FixedUpdates should have happened between the previous Update and this one. If so, multiple FixedUpdates may run in sequence. If not, no FixedUpdates will run. So the FixedUpdate timing is actually linked to the Update timing, but not very predictably.

Generally, I recommend staying away from FixedUpdate and instead handling movement indirectly through the physics system in Update, as anything that needs to happen in FixedUpdate will get aggregated before it needs to be run. For example, if you change a rigidbody's velocity multiple times in Update, then FixedUpdate should still work as expected.

CodePudding user response:

For single event inputs (GetKeyDown) it might be sometimes important to split the behavior and get the Input within Update but apply it in FixedUpdate (again this depends a lot on your use case still).

However, for continues input like GetKey or your GetAxisRaw it doesn't matter where you handle it (again depending on your exact use case of course). MovePosition is recommended to be called in FixedUpdate so in your case you could simply do

private void FixedUpdate()
{
    rb2d.MovePosition(rb2d.position   Vector2.right * Input.GetAxisRaw("Horizontal");
}

What I mean by "it depends on your use case" is that you could achieve the same thing using rather the velocity in which case it wouldn't matter at all whether you do it within Update or FixedUpdate:

//private void Update ()
private void FixedUpdate()
{
    // This is even better since you keep the Y velocity unchanged
    // => Gravity will still work while it wouldn't using MovePosition!
    var velocity = rb2d.velocity;
    velocity.x = Input.GetAxisRaw("Horizontal");
    rb2d.velocity = velocity;
}

for both Update or FixedUpdate the movement will be the same. If you use Update some frames might just have no effect as the velocity is applied in the next FixedUpdate call and in the meantime interpolated using the settings on your Rigidbody.

  • Related