- Home /
OnTriggerStay execution order/rate
Hello!
Is OnTriggerStay executed in different timer rather than FixedUpdate? And is it run in different thread rather than Update function?
I compare distance to checkpoint in OnTriggerStay and if it is smaller than some value, the next checkpoint is selected. All movement actions and distance calculation done in Update or FixedUpdate functions (I tried two ways). According to Unity's help "Execution Order...", it should work fine. But sometimes checkpoint is changed with an old distance value (to previous point) while it has to be recalculated in Fixed/Update function, but it seems this didn't happen.
When I add a check for an Update execution, strange pauses in some movement actions appeared. Is there any error?
Thanks
void Update () {
transform.position=Vector3.MoveTowards(transform.position,hBeacon.position,curSpeed*Time.deltaTime);
distance=(hBeacon.position-transform.position).magnitude;
testBool=true;
}
void OnTriggerStay (Collider other){
if(testBool){
if(other.transform==hBeacon&distance<=0.1F){
hBeacon=Globals.beacon[ind].transform;
}
testBool=false;
}
}
But do you know there is a difference between & and &&. If you want to check if smg AND smg else are true, you do if(smg && smgelse)
if(smg & smgelse) means you are "anding" the binary values of the variables. & alone is a bit operator and operating at the binary level.
Ex (simplified):
var a=1;
var b=2;
if(a&&b) returns true because both are non 0
if(a&b) returns 0
because 00000001 AND 00000010 =00000000 binary
Yes but 01 & 10 = false and 01 && 10 = true. Don't use & unless you are checking for a bit.
Hm... Let's a=null and b=null, then if(a&b) produces false?
No, you get an error. The compiler expects two binary values but null is nothing you would have to convert it from ASCII to Int.
And what will produce if(01001001)? true because it is not 00000000?
yes it does but you need to convert it to int also. I would think the compiler does not consider a binary value here but more likely the 1 001 001 (1 million...)
you would have to use:
var a = System.Convert.ToInt32("01001001",2);
if(a)
The real point is that in C a bool was an int, but in C# a bool is a bool and an int is an int.
You can't do if( someBool & someInt).
//doesn't work
If( true & 1)
Type safety is your friend dont return or use an int when you want true and false
Answer by aliakbo · Aug 26, 2012 at 02:03 PM
I've been struggling with this issue all afternoon!
My OnTriggerStay and Update/FixedUpdate methods were not in sync resulting is split-second undesired effects.
I finally found the solution when I read in the OnTriggerStay docs that this function can be a co-routine. I simply added a WaitForFixedUpdate in the correct location in my OnTriggerStay and it worked. They now both run in sync with each other. This even corrects the issue in Update.
Note that this solution will delay the physics thread, which could slightly affect performance or reliability of the physics solve.
The physics is decoupled from the Update for a reason...use FixedUpdate ins$$anonymous$$d for things that need to be in lockstep with the physics.
There is no physics thread and nothing will be delayed apart from the code after the WaitForFixedUpdate.
Physics runs as a catchup on the main thread.
Answer by aldonaletto · Jun 16, 2012 at 08:06 PM
Collisions are detected in the physics cycle - not sure if before or after FixedUpdate. According to the docs, Unity processes an Update cycle (calling all Update, LateUpdate and coroutines), then start executing physics cycles, adding Time.fixedDeltaTime to the internal physics clock until it reaches the actual Unity clock. Since the physics engine only see its internal clock, it "thinks" to be always running at a fixed pace. If the frame rate is faster than the physics rate, you may have more than one Update cycle without any physics cycle in between (and no collision detection); conversely, several physics cycles may occur between updates when the frame rate is lower than the physics rate.
Anyway, I think you should use only Update, and OnTriggerEnter/Exit instead of Stay:
bool inTrigger = false; // is true while character inside current hBeacon trigger
void OnTriggerEnter(Collider other){ if (other.transform == hBeacon){ inTrigger = true; } }
void OnTriggerExit(Collider other){ if (other.transform == hBeacon){ inTrigger = false; } }
void Update(){ if (inTrigger){ // character inside trigger } }
Thanks! That solution works, but needs additional code for tracking collisions with objects (I also replace CollisionStay with Enter/Exit)...
Thank you!!!!
I was racking my brain all week to figure out the "onTriggerStay" bug I was having... basically it wasn't calling all the time.
Setting up the Bool ins$$anonymous$$d was the fix! So now I just call "enter" and "exit" and let the bool take the place of "stay" ... such a simple solution!!
Answer by fafase · Jun 17, 2012 at 07:10 AM
I ran a little test for info about this with:
var frame :int =0;
function Update(){
Debug.Log("Update "+frame+" "+Time.realtimeSinceStartup);}
function LateUpdate(){
Debug.Log("LateUpdate "+frame +" "+Time.realtimeSinceStartup);
frame++;}
function OnCollisionEnter(other:Collision){
Debug.Log("Collision "+frame+" " +Time.realtimeSinceStartup);}
Here is the result:
Update 44 1.143791
LateUpdate 44 1.145589
Collision 45 1.16041
Update 45 1.162351
To me, it looks like collision occurs on frame 44 to be detected and taken care of before any others on frame 45.
EDIT: Actually the documentation says it all:
So in conclusion, this is the execution order for any given script:
All Awake calls
All Start Calls
while (stepping towards variable delta time)
All FixedUpdate functions
Physics simulation
OnEnter/Exit/Stay trigger functions
OnEnter/Exit/Stay collision functions
Rigidbody interpolation applies transform.position and rotation
OnMouseDown/OnMouseUp etc. events
All Update functions
Animations are advanced, blended and applied to transform
All LateUpdate functions
Rendering
collision occurs on frame 44 to be detected and taken care of before any others on frame 45
So inspite of docs it would be always called before any update func, even fixed? Hm... it seems to be true. So the only way to make it work is to add a distance calculation in the body of "On...Stay" func...
Try this with a OnCollisionStay or OnTriggerStay. In docs they are executed after a fixedUpdate, before an Update.
But if you add a check for the Update cycle end, then it could skip some fixed timesteps. Without this check, it could be run twice before next Update or FixedUpdate cycle.
So the problem was: car touched 1st beacon and distance <$$anonymous$$, the next beacon is selected, Update func must recalculate distance to a 2nd beacon, but ins$$anonymous$$d this ...Stay func reads unchanged distance (to 1st point) and selects 3rd point while skipping 2nd.
The sentence you quote is somehow wrong, I will edit it.
The way it goes is that the collision occurs during frame 44, so update of frame 44 is running when collision happens. In frame 45, the collsion is first detected and processed, then the update is run. If you were to alter a value in your collision then in the update of the same frame it would be the new value.
On the other hand, FixedUpdate seems to be called first.
You would not use FixedUpdate and Update in the same script.
Running the little test I showed would give you the answer.
A command will not be run twice in the same frame.
On the other hand, FixedUpdate seems to be called first.
$$anonymous$$aybe, but as I remember it hadn't worked with a movement&distance calculation in FixedUpdate and checkpoint selection in OnTriggerStay... Or maybe I moved an object in Fixed and calculate distance in Update and that's why it didn't work. I have changed code, so don't have a simple way to test it.
The documentation shows that the Physics is in a loop (while) , when I do the same test with OnCollisionStay and FixedUpdate, LateUpdate is not printing meaning that as long as the object is colliding only the while/Physics section is looping, the rest is waiting.
Exactly! It is strange but I never thought that while in the doc means loop...
There is a new question: how long physic loop could run? $$anonymous$$aximum Allowed Timestep in Time $$anonymous$$anager? But then why did my trigger event fire after 300 frames (~2sec)?