- Home /
Should I be using time.fixedDeltaTime here?
I'm very new and working on a simple fps movement script based on various tutorials I've found. I find my movement is not as completely smooth as I would like it to be. I am wondering if this:
private void Run()
{
vel.z = vInput * speed;
vel.x = hInput * speed;
}
private void FixedUpdate()
{
Run();
Jump();
rb.velocity = transform.TransformDirection(vel);
}
should be using Time.fixedDeltaTime when setting the vel vector's x and z to the key input.
Should I be using deltaTime somewhere here, should I be using SmoothDamp, or Lerp? I don't yet understand exactly where and how I should be applying these tools for the smooth, consistent movement I want. I'll paste the entire (fairly short) script below in case anyone has any pointers for me. Thanks.
using UnityEngine;
public class PlayerMovement_1P : MonoBehaviour
{
private Rigidbody rb;
private Vector3 vel;
private float vInput, hInput, jumpInput;
public float speed, jumpVel, distToGround, downAccel;
public LayerMask ground;
private void Start()
{
if (GetComponent<Rigidbody>())
rb = GetComponent<Rigidbody>();
else
Debug.LogError("The character needs a rigidbody.");
vInput = hInput = jumpInput = 0;
vel = Vector3.zero;
}
private void GetInput()
{
vInput = Input.GetAxis("Vertical");
hInput = Input.GetAxis("Horizontal");
jumpInput = Input.GetAxisRaw("Jump");
}
private void Run()
{
vel.z = vInput * speed;
vel.x = hInput * speed;
}
private void Jump()
{
if (jumpInput > 0 && IsGrounded())
{
vel.y = jumpVel;
}
else if (jumpInput == 0 && IsGrounded())
{
// Zero out y vel when on ground and not jumping
vel.y = 0;
}
else
{
// Not grounded - falling
vel.y -= downAccel;
}
}
bool IsGrounded()
{
return Physics.Raycast(transform.position, Vector3.down, distToGround, ground);
}
private void Update()
{
GetInput();
}
private void FixedUpdate()
{
Run();
Jump();
rb.velocity = transform.TransformDirection(vel);
}
}
Answer by FlaSh-G · Aug 12, 2017 at 09:43 AM
Edit: When writing this answer, I overlooked the fact that you are setting a rigidbody velocity. A velocity is already "distance / time", so multiplying with Time.deltaTime would divide by time again, leaving you with "distance / time²", which is an acceleration, not a velocity. So, in your case, the Rigidbody internally uses Time.deltaTime already when applying its velocity, thus you shouldn't use it. Thanks @senilo for pointing that out.
Original answer:
FixedUpdate does not get called with constant timesteps - that is impossible on modern computers. But it does act like it is - by getting called more or less often in order to have the correct number of calls on average. This allows FixedUpdate code to assume a constant call rate even though there is none, so you don't have to multiply with Time.deltaTime (which, by the way, during FixedUpdate has the same constant value as Time.fixedDeltaTime).
The game will run in a deterministic way using FixedUpdate - and multiplying the (then-)constant factor of Time.deltaTime will not change that in any way.
However, the value still functions as a "per second". If you move by one meter every FixedUpdate, with the default fixed timestep of 0.02, you move 50 meters per second. So putting your speed factor to 1 means 50 m/s, which seems quite arbitrary. If you want a speed of exactly 6 m/s, you might already want to whoop out the calculator. Even worse: If you change your project's fixed timestep at some point, your scripts will change their behaviour. Top speeds will have to be fixed on all objects.
So, multiplying Time.deltaTime in FixedUpdate does serve a purpose: It changes the semantics of the values you set in your script's properties from "per fixedupdate" to "per second" and makes your scripts more robust to changes in the project's fixed timestep. Thus, I recommend using it.
But in this case the velocity is set directly so it doesn't make sense to multiply with the time step
Answer by merkaba48 · Aug 09, 2017 at 10:05 PM
Unsure, and there'll hopefully be a better answer on its way, but have you tried setting the rigidbody's Collision Detection field to 'continuous'? It will be more expensive but it will give better physics calculations; not something you want for most things, but for the player.
Also I notice you are using input to determine whether to add velocity within the fixed update; be warned that input is only updated immediately after the Update() method, and persist until the end of the next Update(). So if for example you pressed Jump and 3 fixed updates occurred before the next update, your fixedupdates will have that same jump input for those 3 updates. You're checking if the player is on the ground so you shouldn't notice the extra jump inputs (and by default there's only about 1 fixed update per update anyway), but I thought I'd mention it. One fix would be to set a bool in Update() that says whether to jump or not, then clear that bool as soon as it's resolved in fixedupdate so future fixedupdates that frame aren't affected.
I just assumed the velocity change should be in FixedUpdate and that getting input should be in Update. Would it make more sense to move something around?
Answer by GeroNL · Jan 24, 2021 at 04:26 AM
Try do like this :
private void FixedUpdate()
{
IsGrounded();
{
private void Update()
{
Input();
Run();
Jump();
rb.velocity = transform.TransformDirection(vel);
}
You can see this life cycle in here : https://docs.unity3d.com/Manual/ExecutionOrder.html
As you can see in the life cycle, the FixedUpdate called multiple times in one cycle, why the reason i put IsGrounded() in the FixedUpdate() is maybe when my character in the ground it not called and throug the object that should called true value.
That is just example for it, but when it's not needed(not troubling/ make a bug like i said before) you can put it in Update() after move or before input, it can gaining more FPS cause it just called one time.
[Edited]
Use Time.deltaTime that called in Update() and Use Time.fixedDeltaTime that called in FixedUpdate().
[Edited]
Hope it helps.
You can use Time.deltaTime anywhere. In a FixedUpdate context, this property will return the same value as Time.fixedDeltaTime. So no need to distinguish.
Yes, FixedUpdate can be called multiple times between one Update, but Update can also happen multiple times between two FixedUpdates. In fact, since FixedUpdate runs an average of 50 times per frame with the default setting, in a 60fps context, Update will be called more often than FixedUpdate.
Putting a few lines of code in Update or FixedUpdate will not create a noticeable difference in fps. However, in your example, you are setting Rigidbody.velocity in Update, which is never a good idea. Either FixedUpdate runs multiple times between two Updates, in which case the velocity is not updates between two movement ticks, or Update runs multiple times between two FixedUpdates, which means that you're overwriting the first value you've set without never even actually applying it, because the rigidbody updates its position with its velocity during the FixedUpdate cycle.
Ahh, it's mean it is call it fixed cause it's steady in certain time and delta time by time per cycle. thanks sir, good to have new thing.
Answer by Igor_Vasiak · Aug 09, 2017 at 10:45 PM
If you want smooth movement you should use Rigidbody.AddForce(). It's like that:
[SerializeField]private float speed;
private Rigidbody rbody;
private float inputH, inputV;
void Start ()
{
rbody = GetComponent<Rigidbody>();
}
void FixedUpdate ()
{
inputH = Input.GetAxis("Horizontal");
inputV = Input.GetAxis("Vertical");
float moveX = inputH * speed * Time.fixedDeltaTime;
float moveZ = inputV * speed * Time.fixedDeltaTime;
rbody.velocity = new Vector3(0, rbody.velocity.y,0);
rbody.AddForce(transform.Forward * moveZ * Time.fixedDeltaTime, ForceMode.Force);
rbody.AddForce(transform.Right * moveX * Time.fixedDeltaTime, ForceMode.Force);
}
Hope I've helped.
Thanks for your suggestion, however I'm looking for unrealistically snappy FPS-style controls, just more consistent, smooth ones than I have. addForce made things very slidey and doesn't seem suited to this type of control scheme.
So, ins$$anonymous$$d of using AddForce try this:
[SerializeField]private float speed;
private Rigidbody rbody;
private float inputH, inputV;
void Start ()
{
rbody = GetComponent<Rigidbody>();
}
void FixedUpdate ()
{
inputH = Input.GetAxis("Horizontal");
inputV = Input.GetAxis("Vertical");
float moveX = inputH * speed * Time.fixedDeltaTime;
float moveZ = inputV * speed * Time.fixedDeltaTime;
rbody.velocity = new Vector3(moveX * Time.fixedDeltaTime, rbody.velocity.y, moveZ * Time.fixedDeltaTime);
}
So I should actually be doing the input * speed part IN fixedupdate? Thanks, I'll try this and see if it helps. :)
Answer by senilo · Aug 12, 2017 at 09:19 AM
Try to apply the velocity directly in Update(), I don't see any reason why you have to do it in FixedUpdate()
The default timestep for FixedUpdate() is 50 Hz, so if your game is running at 60 fps, you don't apply the controls on every frame.
Try this:
private void Update()
{
GetInput();
Run();
Jump();
rb.velocity = transform.TransformDirection(vel);
}
Edit: and decrease the physics time step
There is a reason. Wrote a wall of text about this yesterday: answers.unity3d.com/questions/1391935/timedelta-problems.html?childToView=1392582#answer-1392582
In this case the velocity is set directly so it would not make any difference, but you are right that the physics calculations are still only 50 Hz so it would not help. I have updated the answer with that the time step have to be be decreased