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.
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 FixedUpdate
s should have happened between the previous Update
and this one. If so, multiple FixedUpdate
s may run in sequence. If not, no FixedUpdate
s 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.