Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more..
    Dismiss Notice
  3. Dismiss Notice

IEnumerator, Coroutines and to Capture some action before calling them, Is this the right approach?

Discussion in 'Scripting' started by SadeqSoli, Mar 5, 2021.

  1. SadeqSoli

    SadeqSoli

    Joined:
    Jul 1, 2019
    Posts:
    11
    So I have a array of IEnumerator in unity c# and I want to call them one by one.

    I'm gonna run these in start and call them as the right dialogue and right sequence is here.

    //For capturing Prerun of what is happening moving Backwards
    Code (CSharp):
    1.     void PlotPreRunActsBackward()
    2.     {
    3.         DialogueActsBackward = new IEnumerator[row];
    4.         for (int i = 0; i < row; i++)
    5.         {
    6.             int sequenceNumber = GetSequenceNumber(i);
    7.             if (i == 0)
    8.             {
    9.                 IEnumerator fadeIN_IE = FadeIN(fadeInSprite, sequenceNumber);
    10.  
    11.                 DialogueActsBackward[i] = NewDialogue(fadeIN_IE, i, sequenceNumber);
    12.             }
    13.             //Backward
    14.             else if (i == 3)
    15.             {
    16.                 IEnumerator fadeINOUT_IE = FadeIN_OUT(fadeINOUTSprite, sequenceNumber);
    17.                 DialogueActsBackward[i] = NewDialogue(fadeINOUT_IE, i, sequenceNumber);
    18.             }
    19.             //Backward
    20.             else if (i == 6)
    21.             {
    22.                 IEnumerator fadeINOUTTime_IE0 = FadeIN_OUT(timeLaterSprites[0], sequenceNumber);
    23.                 DialogueActsBackward[i] = NewDialogue(fadeINOUTTime_IE0, i, sequenceNumber);
    24.             }
    25.             //Backward
    26.             else if (i == 8)
    27.             {
    28.                 IEnumerator fadeINOUT_IE = FadeIN_OUT(fadeINOUTSprite, sequenceNumber);
    29.                 DialogueActsBackward[i] = NewDialogue(fadeINOUT_IE, i, sequenceNumber);
    30.             }
    31.             //Backward
    32.             else if (i == 11)
    33.             {
    34.                 IEnumerator closeUp0 = CloseUp(closeUp[0], sequenceNumber);
    35.                 DialogueActsBackward[i] = NewDialogue(closeUp0, i, sequenceNumber);
    36.             }
    37.          
    38.             else
    39.             {
    40.                 DialogueActsBackward[i] = NewDialogue(i, sequenceNumber);
    41.             }
    42.         }
    43.     }
    44.  
    45. //For capturing Prerun of what is happening moving forwards
    46.     void PlotPreRunActsForward()
    47.     {
    48.         DialogueActsForward = new IEnumerator[row];
    49.         for (int i = 0; i < row; i++)
    50.         {
    51.             int sequenceNumber = GetSequenceNumber(i);
    52.             if (i == 0)
    53.             {
    54.                 IEnumerator fadeIN_IE = FadeIN(fadeInSprite, sequenceNumber);
    55.  
    56.                 DialogueActsForward[i] = NewDialogue(fadeIN_IE, i, sequenceNumber);
    57.             }
    58.             else if (i == 4)
    59.             {
    60.                 IEnumerator fadeINOUT_IE = FadeIN_OUT(fadeINOUTSprite, sequenceNumber);
    61.                 DialogueActsForward[i] = NewDialogue(fadeINOUT_IE, i, sequenceNumber);
    62.             }
    63.             else if (i == 7)
    64.             {
    65.                 IEnumerator fadeINOUTTime_IE0 = FadeIN_OUT(timeLaterSprites[0], sequenceNumber);
    66.                 DialogueActsForward[i] = NewDialogue(fadeINOUTTime_IE0, i, sequenceNumber);
    67.             }
    68.             else if (i == 9)
    69.             {
    70.                 IEnumerator fadeINOUT_IE = FadeIN_OUT(fadeINOUTSprite, sequenceNumber);
    71.                 DialogueActsForward[i] = NewDialogue(fadeINOUT_IE, i, sequenceNumber);
    72.             }
    73.             else if (i == 12)
    74.             {
    75.                 IEnumerator closeUp0 = CloseUp(closeUp[0], sequenceNumber);
    76.                 DialogueActsForward[i] = NewDialogue(closeUp0, i, sequenceNumber);
    77.             }
    78.             else
    79.             {
    80.                 DialogueActsForward[i] = NewDialogue(i, sequenceNumber);
    81.             }
    82.         }
    83.     }
    PROBLEM: For instance I call "DialogueActsForward" 2nd number and go back to "DialogueActsBackward" number 1, NOW when Hit Next again to go to "DialogueActsForward" number 2 it works in background but nothing happens visually on the screen AND when I hit next to go to "DialogueActsForward" number 3, Number 2 and 3 are happening visually with each other, btw this is the Next and Prev method calls:

    //For going Forward
    Code (CSharp):
    1. void GoNextVoice()
    2.     {
    3.         StopAllCoroutines();
    4.         PChanger.PlotDialogue++;
    5.         Debug.Log("Dialogue after Next " + PChanger.PlotDialogue);
    6.         if (PChanger.PlotDialogue > row - 1)
    7.         {
    8.             PChanger.PlotDialogue = row;
    9.             Done(true);
    10.             return;
    11.         }
    12.  
    13.         if (DialogueActsForward[PChanger.PlotDialogue] != null)
    14.         {
    15.             StartCoroutine(DialogueActsForward[PChanger.PlotDialogue]);
    16.             Debug.Log("Dialogue Next " + PChanger.PlotDialogue + " is OK!");
    17.         }
    18.         else
    19.         {
    20.             Debug.Log("Dialogue Next " + PChanger.PlotDialogue + " is null!");
    21.         }
    22.     }
    23. //For going Backward
    24.     void GoPrevVoice()
    25.     {
    26.         StopAllCoroutines();
    27.         PChanger.PlotDialogue--;
    28.         Debug.Log("Dialogue after Prev " + PChanger.PlotDialogue);
    29.         if (PChanger.PlotDialogue < 0)
    30.         {
    31.             PChanger.PlotDialogue = 0;
    32.             return;
    33.         }
    34.         if (DialogueActsBackward[PChanger.PlotDialogue] != null)
    35.         {
    36.             StartCoroutine(DialogueActsBackward[PChanger.PlotDialogue]);
    37.             Debug.Log("Dialogue Back " + PChanger.PlotDialogue + " is OK!");
    38.         }
    39.         else
    40.         {
    41.             Debug.Log("Dialogue Back " + PChanger.PlotDialogue + " is null!");
    42.         }
    43.     }
     
    Last edited: Mar 5, 2021
  2. JoshuaMcKenzie

    JoshuaMcKenzie

    Joined:
    Jun 20, 2015
    Posts:
    897
    IEnumerators are typically disposed after the coroutine that has ran them has stopped/finished. Unless you are feeding a class that implements IEnumerator into the coroutines (and not a function that returns an Ienumerator as is the typical convention) you can't reset the state of the IEnumerator before its run again in the next StartCoroutine call. And making a resetable IEnumerator class is often alot more work than its worth. So the typical practice is to just discard that previous iterator and make a new one, better yet, don't store it in the first place.

    You'll want to grab a new instance of the IEnumerators you use each time you call StartCoroutine. For example instead of DialogueActsBackward being of type IEnumerator[], you can have it be of type System.Action<IEnumerator>[] and have it store an array of lambadas which will generate the IEnumerators you need on request.

    instead of :
    Code (CSharp):
    1.  
    2.             int sequenceNumber = GetSequenceNumber(i);
    3.             ...
    4.             IEnumerator fadeINOUT_IE = FadeIN_OUT(fadeINOUTSprite,sequenceNumber);
    5.             DialogueActsBackward[i] = NewDialogue(fadeINOUT_IE,i,sequenceNumber);
    6.  
    you'd want:
    Code (CSharp):
    1.  
    2.             int sequenceNumber = GetSequenceNumber(i);
    3.             int closureIndex = i;
    4.             ...
    5.             DialogueActsBackward[i] = () =>
    6.             {
    7.                 IEnumerator fadeINOUT_IE = FadeIN_OUT(fadeINOUTSprite,sequenceNumber);
    8.                 return NewDialogue(fadeINOUT_IE,closureIndex,sequenceNumber);
    9.             };
    and your prev and next functions would start a coroutine like this:
    Code (CSharp):
    1. //Notice I added an extra parenths at the end, as if I'm calling a method, cause I am
    2. StartCoroutine(DialogueActsForward[PChanger.PlotDialogue]());
    So the IEnumerators themselves are not cached, the instructions to make them are.

    Also notice that inside the lambada we don't use "i" and instead use "closureIndex". This is important rule to remember when defining lambadas inside loops, if we didn't do this then ALL the lambadas would use the very last value i gets assigned to (in this case all lambadas would treat i as "row-1" everytime they run). All variables defined outside the loop are shared and lambadas will use whatever value those variables are set to when they are called, but variables defined inside the loop's scope are closured and the lambadas will always use the exact values they were set to at the time when the lambada was defined.
     
  3. SadeqSoli

    SadeqSoli

    Joined:
    Jul 1, 2019
    Posts:
    11
    @JoshuaMcKenzie Actually I just handled it exactly like you said in the first place at fly and it worked just fine but I was so curious that why IEnumerators are not working and you just made it clear for me and I also used the Action lambada solution and it also worked. Thanks for your help, Hope this thread helps also different people with the same problem. :)