I know if I do too many thing in update() the consequence would be dropped frame rate below the target frame rate. But what would happen if I do the same thing in fixedUpdate()?
Would it cause Unity's physicsEngine to mess up, or would it crash the program?
The answers and comments were very helpful, but they lack a clear, informative answer to my question. Everyone knows bad things will happen when you put too much work load in the FixedUpdate() loop, my question was to ask what bad thing will happen then.
Since I finally got my hand on a computer I decided to make some test on my own. Just for reference this is what I used to test:
public class TestFixedUpdate : MonoBehaviour {
public int loopNo = 500000;
private int noOfCall = 0;
private int collisionTimes = 0;
private void FixedUpdate()
{
if (noOfCall > 100) return;
float time = Time.timeSinceLevelLoad;
for (int i = 0; i < loopNo; i++) {
Quaternion.Slerp(Quaternion.identity, Quaternion.FromToRotation(Vector3.up, Vector3.forward), Mathf.Abs(Mathf.Sin(Time.timeSinceLevelLoad)));
}
Debug.Log(Time.timeSinceLevelLoad.ToString("0.00"));
if (noOfCall > 99) Debug.Log("Simulation finished. Times collided:" + collisionTimes);
noOfCall++;
}
private void OnCollisionEnter(Collision collision)
{
if (noOfCall > 100) return;
collisionTimes++;
Debug.Log("Times collided:" + collisionTimes);
}
}
I put it on a sphere that will continuously bounce on a plane. The test was made by changing the function from FixedUpdate() and Update() and compare the differences.
The main difference I found out was that in the case of FixedUpdate(), Unity's simulated Time (the game world's time) is delayed out of sync with actual time. In other words, any function that depends on Unity's Time system will act as if the whole world has slowed down.
Also:
Unity reports the same frame rate for both cases, even though for the FixedUpdate() case it is apparent that the actual frame rate - the frame per real world second - is significantly lower.
Aside from slowing down, collision detection and physics simulation logic seem to work as usual. Bodies that should collide still collide; acceleration, force application etc still work. Rigidbodies that don't jump through a collider in 20ms (Unity's ms) still collide and bounce back as usual.
The Maximum Allowed Timestep option in Project's settings define the maximum amount of (Unity's simulated time) before a frame must be draw (I never knew what it was for before). Clarification: if I set it to 0.5 second, then no matter how much code I put into both functions, the logic update step (Update()) will be called immediately after a FixedUpdate() round has simulated the 0.5-th second, and then the scene will be rendered.
The engine will stall while processing a heavy load (e.g. if you do an infinite loop) inside any function. Things which rely on Time.DeltaTime will start acting up if the frame rate drops too low. It won't really matter whether that's Update or FixedUpdate.
What you can do if you need a process to run a heavy load is to use an coroutines e.g. IEnumerator function and yield, which allows you to split processing over a number of frames, or to have some function called via a callback. e.g. if you have an AI check path 5 times a second you can either handle that in Update with a counter each frame or you can schedule a callback.
Basically, there's going to be limit in how much code you can run per frame without degrading performance. Clever rewriting should make that unnecessary. See if you can cache results of calculations or pre-calculate as much data outside play as possible.
Related
I'm a senior software engineer, but completely new to Unity programming. I've been teaching myself Unity for a few weeks by writing some SteamVR toys for myself. I wanted to ask about Unity's standard built-in ways to improve frame rate for a program with a lot of intensive physics calculation.
In my current VR scene, I have a ball with a Rigidbody on it. When I pick it up and throw it, I let it move naturally, but I apply small forces on every Update() call to adjust the landing position and always hit a target.
I saw my framerate take a big dive, so I wrote my own function to throttle the updates, limiting them to 5 per second. The question is, is there some standard Unity behavior that I should be using instead of rolling this code myself?
In my throwing script, I maintain a bunch of top level variables and update them first to decide whether I should do calculations on the current frame.
private void updateCalculationFrame() {
isCalculationFrame = Time.time > nextCalculationTime;
while (nextCalculationTime < Time.time) {
nextCalculationTime += (1 / calculationsPerSecond);
}
}
On each frame, I run this function, then if isCalculationFrame is true, I proceed to calculate and add force vectors. I just wonder if I am overlooking some more standard way to do this with less code? I feel like this must be a very common thing to try to do.
The code you have there will freeze the Unity until the loop is finished. You shouldn't do this at all.
You could simply set a new Time.fixedDeltaTime. By default it is usually about 0.02 but you can set it to anything you want.
The interval in seconds at which physics and other fixed frame rate updates (like MonoBehaviour's FixedUpdate) are performed.
...
Note that the fixedDeltaTime interval is with respect to the in-game time affected by timeScale.
There seems to be a lot of confusing/conflicting advice out there about when you should or should not multiply a quantity by Time.deltaTime. So I was wondering, as it pertains to the Unity physics system, when should you multiply by Time.deltaTime?
I understand that Time.deltaTime is used to make certain actions framerate independent, but there are some situations where it isn't clear whether an action is framerate independent. For instance:
Doing rigidbody.velocity += acceleration*Time.deltaTime; in FixedUpdate. Since FixedUpdate runs at a constant timestep, does this make the multiply by Time.deltaTime unnecessary?
Doing rigidbody.AddForce(force*Time.deltaTime, forceMode);. How do the various ForceModes effect this?
I've seen solutions to individual situations, but it would be nice if there were a simple intuition which could address all of these situations.
The intuition
Multiplying by Time.deltaTime is used to make an instantaneous operation act in a continuous (or "smooth") way.
An instantaneous operation will cause a certain quantity to "jump" to a different value. The following operations are instantaneous:
Rigidbody.[position|velocity|rotation|angularVelocity] += x;
Rigidbody2D.[position|velocity|rotation|angularVelocity] += x;
Rigidbody.Add[Force|Torque](x, ForceMode.[Impulse|VelocityChange]);
Rigidbody2D.Add[Force|Torque](x, ForceMode2D.Impulse);
All the above operations cause a quantity to instantly jump by x, irrespective of the length of the frame.
In contrast, the following operations are continuous:
Rigidbody.Add[Force|Torque](x, ForceMode.[Force|Acceleration]);
Rigidbody2D.Add[Force|Torque](x, ForceMode.Force);
Rigidbody.velocity = x; (continuous from the perspective of Rigidbody.position. i.e. setting the velocity will not make Rigidbody.position suddenly jump to a new value)
All the above operations are applied over the course of the frame (at least conceptually this happens; what the physics system does internally is out of the scope of this answer). To illustrate this, Rigidbody.AddForce(1, ForceMode.Force) will cause a force of 1 newton to be applied to an object for the entire frame; there will be no sudden jumps in position or velocity.
So when do you multiply by Time.deltaTime?
If you are using a continuous operation, you should almost definitely not be multiplying by Time.deltaTime. But if you are using an instantaneous operation, the answer depends on if the operation is being used in a continuous way.
Example 1: Explosion
void Explode() {
rigidbody.velocity += explosionAcceleration;
}
Here you should not be multiplying by Time.deltaTime since Explode() gets called just once. It is not meant to be applied over a series of frames.
Example 2: Moving
void Update() {
rigidbody.position += velocity * Time.deltaTime;
}
Here you do have to multiply by Time.deltaTime because the object is supposed to move continuously over time, and you are also using an instantaneous operation. Note that this could be replaced with a continuous operation, and remove the need for multiplying by Time.deltaTime:
void Update() {
rigidbody.velocity = velocity;
}
Although this isn't entirely equivalent to the original, since it ignores the previous value of rigidbody.velocity.
Example 3: Accelerating
void Update() {
rigidbody.AddForce(acceleration*Time.deltaTime, ForceMode.VelocityChange);
}
Here you should be multiplying by Time.deltaTime because you want the velocity to increase at a consistent rate frame by frame. Note that this is precisely equivalent to:
void Update() {
rigidbody.AddForce(acceleration, ForceMode.Acceleration);
}
This code applies the acceleration over the course of the whole frame. This code is also (in my opinion) cleaner and easier to understand.
What about FixedUpdate?
Being in FixedUpdate does not effect any of the above advice. Yes, you could theoretically get away with never multiplying by Time.deltaTime since the time between frames would always be the same. But then all your units would have to be dependent on the fixed frame rate. So for example if you wanted to move at a rate of 1 m/s with 60 frames per second, you would have to add 1/60=.01666 to the position each frame. And then imagine what happens if you change your fixed timestep. You would have to change a bunch of your constants to accommodate.
Executing code in FixedUpdate does not suddenly make that code framerate independent. You still have to take the same precautions as in Update.
As a side note, you do not need to replace Time.deltaTime with Time.fixedDeltaTime inside FixedUpdate because Unity already does this substitution.
Conclusion
Only multiply by Time.deltaTime if you want an instantaneous operation to act smoothly over a series of frames.
Many times, you can avoid using Time.deltaTime by using continuous operations, which are often more intuitive (see examples 2 and 3). But this of course depends on the context.
A simple way to think about this is to determine:
Are objects' transforms manipulated directly?
When an object is being moved directly via its transform.position and transform.rotation components, manipulation of the transform should occur in Update(), which runs once per drawn frame. The developer should build their game with the expectation that the Update/frame rate varying between zero and the game's maximum frame rate. The way to accomplish this is by factoring in the time between now and previous frame into the movement (step) for each update/frame.
Thus, manipulations to the transform.position and transform.rotation should factor in Time.deltaTime and should occur within Update().
Are objects being manipulated with physics?
In this case, forces and torques should be applied by calling Rigidbody.AddForce() or Rigidbody.AddTorque() in FixedUpdate(). FixedUpdate() can be expected to occur at a fixed/guaranteed rate, which Unity defaults to 50 times per second (this can be adjusted within the Physics settings of your game project).
To complicate things a bit, when AddForce() and AddTorque() are called with ForceMode.Force (default) or ForceMode.Acceleration, the value provided for the force or torque parameters will be interpreted as amounts for one entire second, so these functions will adjust the value (a force/torque or acceleration/angular acceleration) for one fixed time step (i.e., x 0.02s with the default Unity Physics fixed update rate).
In case you are curious about ForceMode.Impulse or ForceMode.VelocityChange, these will interpret the force or torque as the amount to apply within that fixed time step (i.e. the value will not be adjusted with respect to time).
I have a line that is applying force to the player. The force is applied in an Update() while the player is in the Roll animation state.
if (anim.GetBool("isRolling") == true && anim.GetBool("IsGrounded") == true && canRoll == false)
{
rb.AddForce(transform.forward * rollLength, ForceMode.Force);
}
I am targeting two devices, one with high framerate and one with low framerate. On the one with low (30 fps) framerate, it works fine, but on the high framerate (in the 100s) the player goes too far too fast. I have read that Time.deltaTime will divide the force, which doesn't help me.
What can I do to fix this issue?
Addforce doesn't add Force in physical sense as much as it adds energy: you should control amount and frequency byt Time.deltaTime which makes single call time-dependent, but also you should keep in mind that FixedUpdate exists - it works like a classic Update but it's guaranteed to have constant time in between each calls (equal Time.fixedDeltaTime). Generally speaking if you manipulate phisics in each frame you most likely want to use FixedUpdate instead of Update
But honestly I would considered if addForce is good idea for a rolling mechanic in the first place: I feel like it would be better idea to use Rigidbody.velocity or Rigidbody.Move()
As said above: "AddForce" doesn't really adds force, but energy instead so you should scale it using Time.deltaTime
When doing physical calculations in unity it is recomended to do them inside FixedUpdate, as it is guaranteed to have constant rate of activation which allows you to avoid certain problems that are often for physics with even small framerate fluctuation and correct usage of Time.deltaTime
In my board game, the points are given by throwing 7 sea-shells cowry shell. These shells are dropped onto a sphere in Unity so they get rolled over randomly to different places. Once the rigidbody.isSleeping() returns true, I do a Raycast(from the belly side downwards) to figure out the orientation of the shell. If it is NOT a hit we know the shells belly is turned upside which means a point.
All is good and very realistic when in single player mode. Reason is I just activate the gravity of the shells and they dropped on to sphere, gets rolled randomly and when stopped i get the marks as stated above.
Now the problem is I am making the game multiplayer. In this case, I sent the randomly generated marks from the server and client will have to animate the shells to represent the marks. For example, if server send 3, out of 7 shells, 3 should have it's belly turned upside.
Trying to do this has been a major problem for me. I tried to transform.Rotate() when the velocity is reduced but it was not very reliable and sometimes acts crazy. Rotating afterrigidbody.isSleeping() works but very unrealistic.
I know I am trying to defy physics here, but there may be some ways to achieve what I want with minimum artificial effect.
I actually need some ideas.
Update - 1
After infor I receive below, I did found some information here, some advanced stuff here. Since the latter link had some advanced stuff, I wanted to start small. So I followed the first link and did below test.
I recorded the position, rotation & velocity of the sea shell with autosimulation enabled and logged them to a file. Then i used the Physics.Simulate() for the same scenario and logged the same.
Comparing the two tells me that data in both cases are kind of similar. So seems like for my requirements I need to simulate the sea-shell drop and then apply that sequence to the actual object.
Now my problem is how can I apply the results of physics.simulate() results (position, rotation, velocity etc..) to the actual sea-shell so the animation can be seen. If I set the positions to my gameobject within the simulation loop nothing happens.
public void Simulate()
{
rbdy = GetComponent<Rigidbody>();
rbdy.AddForce(new Vector3(0f, 0f, 10f));
rbdy.useGravity = true;
rbdy.mass = 1f;
//Simulate where it will be in 5 seconds
int i = 0;
while (simulateTime >= Time.fixedDeltaTime)
{
simulateTime -= Time.fixedDeltaTime;
Debug.Log($"position: {rbdy.position.ToString()} rotation: {rbdy.rotation.ToString()} Velocity {rbdy.velocity.magnitude}");
gameObject.transform.position = rbdy.position;
Physics.Simulate(Time.fixedDeltaTime);
}
}
So, how can I get this simulated data applied to actual gameobject in the scene?
Assume Physics are deterministic, just set the velocity and position and let it simulate on each client. Output should be the same. If the output differs slighly, you could adjust it and it may be only barely noticable.
Physics.simulate may be interesting to read, even if it's kind of the opposite of what you want.
You can throw in the client, record the steps in realtime or using physics.simulate (see point 2) and transmit the animation data as binary - then use it in the other clients to play the animation.
I make a 2D-game. In this game, I have a projectile, which I move the fires by myself like this:
void Update()
{
gameObject.transform.position = new Vector3(
gameObject.transform.position.x + baseVelocity * Time.deltaTime,
gameObject.transform.position.y + baseVelocity * Time.deltaTime,
gameObject.transform.position.z);
}
And also, I use void OnTriggerEnter2D(Collider2D other) to know when collisions occurs.
The problem is when game running on a weak phone with 30-FPS it won't detect collision, while same fire in an 60-FPS phone will collide.
I think this is because the fires move 2x more in 30-FPS phones.
One option was use FixedUpdate() method for moving fiers, but it gave me jerky movement, and I used Update() method for moving because it gives me smooth movement(in both of them I used Time.deltaTime).
Can you please suggest me how make more accurate while using smooth movement?
like move object in Update() method but check object position in more(offset) positions than where it is!
I forget to note that I changed the value of Fixed TimeStep to 0.01 for getting more accurate physics.
Thanks in advance.
edit:
I finally end up with using FixedUpdate() for move objects by myself, for so many reasons I can't use Physics engine, I set FixedUpdate TPS(tick per second) around 60 to some how be match with my 60 FPS Update (and still can't figure out why increase FixedUpdate TPS will make object movement jerky!).
And will keep this question open for finding better answer.
You seem to be doing the physics manually. The issue with manually updating the position is that you don't know about the position of your projectile between frames. Even if you were to use FixedUpdate, you could still be in the situation where two FixedUpdate calls cause your projectile to miss an object.
So instead of manually updating the position, you should use a RigidBody2D, with the collision detection set to "Continuous". A continuous collision detection will interpolate object collision in between physics update cycles, so you hit your target even at very high speeds. Also, this solution does not depend on frame rate.
Note that the above will only work if you don't manually update your positions yourself. That is because the physics engine uses velocity to calculate collision in between physics update cycles.
So instead of updating the position yourself (which is bad for physics), use forces instead.
Or alternatively, if you don't want to mess with forces, update the velocity instead:
GetComponent<RigidBody2D>().velocity = baseVelocity;