- Home /
Why is transform.position giving a different result when in Update and a coroutine?
Basically, I have dragged a bone into the inspector and I'm using Debug.DrawRay to visualize the bone's position in the scene view. But for some reason, when using Debug.DrawRay in a coroutine, it doesn't follow the bone properly. The ray drawn from Update() follows the bone perfectly throughout the animation, but the ray drawn from the coroutine doesn't. What am I missing?
The thing I don't understand is that they are both starting at visionTransform.position so I expect to see them originate from the same place, but they don't.
void Update() {
Debug.DrawRay(visionTransform.position, Vector3.up, Color.blue);
}
IEnumerator Test() {
while (true) {
Debug.DrawRay(visionTransform.position, Vector3.up, Color.red);
yield return 0;
}
}
The weird thing is though, the ray drawn in the coroutine sometimes snaps to the correct position.
Answer by WintryBlaze · Nov 29, 2018 at 10:52 AM
So the issue seemed to be with the asset FinalIK, specifically AimIK, which is a component that manipulates the spine bones to point a weapon precisely at a target. Turns out I needed to uncheck the "Fix Transforms" option. This fixes bones to their initial state each Update() which I assume is why the coroutine was showing the bone at its initial position, since it runs after Update(). Thanks to everyone who commented, it made me think about what the issue could be.
Answer by mayur7garg · Nov 28, 2018 at 06:24 PM
It might be because the Update and the Coroutine are being called at different frequencies. Update is being called every frame whereas coroutine much more quickly. Try using yield return new WaitForSeconds(Time.deltaTime);
and see if that improves your case.
Thanks, I tried it but still got the same problem. I believe coroutines which yield return 0 or null always run after update anyway.
How about yield return new WaitForEndOfFrame();
? Wouldn't that be more accurate/reliable?
This answer is based on a misconception - Coroutines get an update once per frame, just the same as the Update function.
And yes, using Time.deltaTime there also makes little sense (wait for as long as the previous frame took... why?!). yield return null (or WaitForEndOfFrame) should work fine.
Thank you for clearing this up. I thought they ran as fast as possible and users were responsible of the ti$$anonymous$$g through the WaitFor... calls. So this means WaitForSeconds only gets as accurate as the nearest frame to the specified time?
Yes WaitForSeconds just skips as many frames as it takes to get to the total duration you specify. It will almost always take a fraction longer, of course. You can't predict how long each frame is going to take, but you do know how long the last one took (Time.deltaTime) so if you need to know how long was actually waited for you can work it out retrospectively (i.e. after the waitforseconds)
The Time class keeps track of the time between the start of one frame and the next- that's what deltaTime is.
That s wrong Update is called once per frame no more no less, exactly once per frame. Now coroutines can be "paused" based the yield statment provided, ex.
IEnumarator UpdateRoutine(){
for(;;){
//code
yield return null;
}
}
is equivalent to Update() with main difference it is called afterwards (but in the same frame)
Anyway, for the question try to use exact same statements (either Vector3.up, or Vector3.forward, not both)
As for WaitForEndOfFrame won't be wrong as AnimationInternalUpdate(if root motion used) occure before it and Update before that thus it is closer to LateUpdate? execution order
You are correct about the co-routines always being after update as seen in the Unity docs: https://docs.unity3d.com/$$anonymous$$anual/ExecutionOrder.html
I'm afraid you've given very little to go off in the way of being able to help debug the issue. Can you provide some screen shots of the render/values? Why are you drawing the ray from separate functions?
Is it necessary to render the forward vector after the update due to some other calculations not seen here? Perhaps the LateUpdate function would be a better option?
I was wondering about LateUpdate, but that runs after the animation update, whereas both Update and Coroutine run before it. So it's hard to see how they could have different values (unless something else is changing the position). I would definitely Debug.log the 2 positions just to see whether it's the position that's different or something in the rendering of the line.