Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Waiting for a method to signal it is done before launching it again

Discussion in 'Scripting' started by gdennis, Dec 17, 2014.

  1. gdennis

    gdennis

    Joined:
    Oct 22, 2014
    Posts:
    17
    I am making a visualization in C# where there are a lot of gamemove related 'actions'. An action can be 'walk to', 'say to' or 'pick up' etc etc. If the story I want to visualize goes like this for example:

    - Player walks to NPC1.
    - Player says to NPC1.



    In this case i obviously want the first action (sentence) to be completed before starting the second one. My code looks as follows:

    Code (CSharp):
    1.     void Update () {
    2.         parseScenario ();
    3.     }
    The definition for the parseScenario function is the following: (small theoretical background (since the implementation is a bit different): entry is a list which contains a number of gamemoves (sentences) to complete. Look at this like a parent list, since each of these lists can contain a number of other gamemoves (sentences) to complete, this is indicated by a _next field which is the next one to do)


    Code (CSharp):
    1.   public void parseScenario () {
    2.         foreach (string e in entry) {
    3.             parseEntryLine(e);
    4.         }
    5.     }
    The parseEntryLine method looks like this:


    Code (CSharp):
    1. public void parseEntryLine (string gm_label) {
    2.         currentGM = findGameMoveByLabel (gm_label);
    3.         if (currentGM.isBrick ()) {
    4.             //Interprete it and perform the animation for it
    5.             animateExpr(currentGM);
    6.  
    7.             //Check if it has a next
    8.             if (currentGM._next != null) {
    9.                 parseEntryLine (currentGM._next);
    10.             }
    11.         }
    12.     }

    And the animateExpr method is just a function which contains a really big switch statement. Based on what the contents of the 'action verb' is, I start a method which performs the action in here.

    Now the problem is that obviously when I run it like this the entire story just gets executed immediately.

    I cannot figure out how to wait for an action to complete before starting a new one.
    Please note that these actions do not have a fixed timespan. (Some require input from the player as well).

    I hope the question is clear, if not please ask me to make it more clear.
     
  2. fire7side

    fire7side

    Joined:
    Oct 15, 2012
    Posts:
    1,819
    The simplest way I know is to set a bool while something is happening and then test for it with a coroutine every half second or whatever. Some things, like animations, already have a "isplaying" property, same with sounds, otherwise you need a trigger of some kind.
     
  3. Sbizz

    Sbizz

    Joined:
    Oct 2, 2014
    Posts:
    250
    You should use coroutines.

    Code (CSharp):
    1. public IEnumerator parseEntryLine (string gm_label) {
    2.         currentGM = findGameMoveByLabel (gm_label);
    3.         if (currentGM.isBrick ()) {
    4.             //Interprete it and perform the animation for it
    5.             yield StartCoroutine(animateExpr(currentGM));
    6.             //Check if it has a next
    7.             if (currentGM._next != null) {
    8.                 parseEntryLine (currentGM._next);
    9.             }
    10.         }
    11.     }
    And your animateExpr should be a coroutine which executes the animation and wait until it finishes.
     
  4. gdennis

    gdennis

    Joined:
    Oct 22, 2014
    Posts:
    17
    Thank you for your answer Sbizz, I read about coroutines but I did not know if that is what i needed or not! What are the changes required in the animateExpr function to make this work?
     
  5. A.Killingbeck

    A.Killingbeck

    Joined:
    Feb 21, 2014
    Posts:
    483
    It needs to return an IEnumerator, the same way Sbizz has written the parseEntryLine
     
  6. Sbizz

    Sbizz

    Joined:
    Oct 2, 2014
    Posts:
    250
    I don't know what you're doing in your function, but something like this:

    Code (CSharp):
    1. public IEnumerator myFunction() {
    2. myAnim.play()
    3.  
    4.     while (myAnim.isPlaying()) {
    5.         yield return null;
    6.     }
    7. }
    Kind of pseudo-code; you play your animation and the loop condition checks if the animation is still playing. If it does, you ask to Unity to "come back inside the scope" the next frame ("yield return null"). DO NOT try to loop without a yield statement, you will crash Unity. You can break a coroutine with "yield return break;".

    Code (CSharp):
    1. public IEnumerator myFunction() {
    2. if (myAnim == null) {
    3.     yield return break;
    4. }
    5.  
    6. myAnim.play()
    7.  
    8.     while (myAnim.isPlaying()) {
    9.         yield return null;
    10.     }
    11. }
    And you can stop a coroutine by stopping the animation ;)
     
    gdennis likes this.
  7. gdennis

    gdennis

    Joined:
    Oct 22, 2014
    Posts:
    17
    Thanks a lot for your help Sbizz and A. Killingbeck
     
  8. Sbizz

    Sbizz

    Joined:
    Oct 2, 2014
    Posts:
    250
    PS: I did 2 mistakes, it's not yield return break but yield break and it's also not yield StartCoroutine(..) but yield return StartCoroutine(..)! ;)