Search Unity

WaitForEndOfFrame has Strange Behaviour

Discussion in 'Scripting' started by CorneliaXaos, Feb 8, 2018.

  1. CorneliaXaos

    CorneliaXaos

    Joined:
    Mar 1, 2017
    Posts:
    7
    So I have a coroutine that's handling some movement logic for one of my GameObjects. Everything works fine when the Game Window is visible in the editor.. but there's some really loopy things that happen when it's not (like when you switch to the Scene view to see things there and it obscures the Game view).

    First, a little code snippet. I have a coroutine (a pair of them actually) that do something along the lines of the following:

    Code (csharp):
    1.  
    2. private IEnumerator DoThingX()
    3. {
    4.     // set up thing X
    5.     while (!DoneWithThingX()) {
    6.         yield return new WaitForEndOfFrame();
    7.         // Do some updating here.
    8.     }
    9.  
    10.     StartCoroutine(DoThingY());
    11. }
    12.  
    13. private IEnumerator DoThingY()
    14. {
    15.     // similar to DoThingX
    16. }
    17.  
    In this way I'm encoding some sort of miniature state machine for my logic, but on to the problem:

    As I've said, it works fine in the editor (and in a build!) but when in the editor it only works correctly when the Game view is visible and being rendered (I didn't test this for the built version when hiding the game window). I did some digging around and looked up the scripting API for that `WaitFor*` object, and found that it runs "after all cameras and GUI is rendered, just before displaying the frame on screen".

    I then added a `Debug.Log` call just before the yield call and discovered that as soon as the Game view is hidden (and, consequently, frames probably stop rendering) the Debug logs stop. It looks as if, while in editor, you can get drastically different behaviour from your code depending on whether or not the cameras are actually being rendered when using this yield instruction.

    I just want to know.. is this intentional? Should I use some other `WaitFor*` object instead of `WaitForEndOfFrame`? I didn't want to use `WaitForSeconds*` as they don't seem appropriate since I need to do this updating (or should do the updating) every frame.

    A few things to point out: I'm doing this in 2017.3.0p2, Linux Beta Editor. I don't have access to a Windows Machine to test if this also occurs in the Windows version, and it seemed like it might be appropriate to put here as it might be intended behaviour.

    For now, I'll just switch to `yield return null` as that doesn't seem to have the same problem.
     
  2. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    There's another older thread, which I can't find, where WaitForEndOfFrame works funny (I think that's the one.) From memory, there's no longer any reason to use it - the only use is capturing a screenshot, and you can do that another way now - so the Unity team may have forgotten to maintain it.

    The normal option is yield return null, which waits 1 Update(). The less common one is waiting a physics step. For cases you really need frames, one of the On*Render should work, instead of a coroutine.
     
  3. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    It can be useful if you need something done after LateUpdate, for example.
     
    MilenaRocha likes this.
  4. tmendez

    tmendez

    Joined:
    Oct 12, 2015
    Posts:
    39
    @Owen-Reynolds and if `yield return null` waits forever, that means that the gameObject is disabled, right? I'm getting that behavior on a script after coming back from a different application on Android
     
  5. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    coroutines and disabling/inactive-ing is a mess. It seems like those usually abort the co-routine, even if the docs say it won't. Restarting the application? Seems like a mess. I wouldn't count on coroutines to handle that.
     
  6. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    If the behaviour's gameobject is disabled (from which coroutine is started), coroutine stops running on it.

    So no. It will not wait forever, it will simply stop.
     
    tmendez likes this.