3

So i've got a problem with IEnumerators with the yield return Talking call at the end of the options function. The talking function is then later set to yield return true when the text file reaches a line that should end the option. But the options function doesn't continue from the yield return talking call at the end and just stops even though the talking function returns true.

Edits:

So the problem is the options function doesn't respond to the talking function being set to true in the yield statement at the end of the function.

I've used breakpoints to make sure options isn't called multiple times and that the talking function reaches the yield return true. Just the options function never continues from the yield statement.

Ive included both the functions below I can add the whole c# script and the text file if needs.

    IEnumerator Talking(string[] text_file, int line)
    {
        while (line != text_file.Length)
        {
            if (text_file[line].Split(' ')[0] == "Keyword")
            {
                var key = text_file[line].Split(' ')[1];
                switch (key)
                {
                    case "Option":
                        yield return Option(text_file, line);
                        break;
                    case "End":
                        End();
                        yield break;
                    case "Code":
                        line++;
                        Code(text_file[line]);
                        break;
                    default:
                        print("Keyword " + key + " not reconsised");
                        break;
                }
            }
            else if (text_file[line] == "End_Option")
            {
                line++;
                yield return true;
            }
            output_Text.DisplayText(text_file[line]);
            while (!controller.click)
            {
                yield return null;
            }
            line++;
        }
    }

    IEnumerator Option(string[] text_file, int line)
    {
        yield return new WaitForEndOfFrame();
        var options = 2;
        int option_start = line;
        int option_1 = 0;
        int option_2 = 0;
        line++;
        var split = text_file[line].Split('|');
        output_Text.Display_Options(split[0], split[1]);
        while (!controller.click)
        {
            yield return null;
        }
        line++;
        while (options != 0)
        {
            while (text_file[line] != "End_Option")
            {
                option_1++;
                line++;
            }
            line++;
            options--;
            while (text_file[line] != "End_Option")
            {
                option_2++;
                line++;
            }
            line++;
            options--;
        }
        while (output_Text.choice == 0)
        {
            yield return null;
        }
        if (output_Text.choice == 1)
        {
            output_Text.choice = 0;
            line = option_start + 1;
        }
        if (output_Text.choice == 2)
        {
            output_Text.choice = 0;
            line = option_start + 2 + option_1;
        }
        yield return Talking(text_file, line);
        line = option_start + 3 + option_1 + option_2;
        yield return true;
    }
}

RedPandas
  • 33
  • 4
  • 1
    why IEnumerator as opposed to IEnumerable. With IEnumerator you have to make sure to dispose correctly otherwise nasty things happen – pm100 Feb 19 '22 at 00:03
  • It looks like you're using this for a unity coroutine. What are you trying to achieve with `yield return true`? – Ruzihm Feb 19 '22 at 00:49
  • @pm100 I'm guessing it's for interfacing with unity's [coroutine API](https://docs.unity3d.com/Manual/Coroutines.html). `WaitForEndOfFrame` is a pretty big clue. – Ruzihm Feb 19 '22 at 00:50
  • @Ruzihm I know nothing about unity other than its a game engine, so if I made a booboo ignore me :-) – pm100 Feb 19 '22 at 00:54
  • With the yield return true I was hoping to go back to the option script and change the line the text file once the end of the option was reached – RedPandas Feb 19 '22 at 01:04
  • @RedPandas If you mean to exit the coroutine early, you probably mean to use `yield break;` then. – Ruzihm Feb 19 '22 at 01:36
  • 1
    Does this answer your question? [How to stop co-routine?](https://stackoverflow.com/questions/25204035/how-to-stop-co-routine) – Ruzihm Feb 19 '22 at 01:37
  • In general it looks to me like you should have one "master routine" calling both of these .. currently both IEnumerators could end up in a state where they yield each other in an end less forth and back loop between them which could sooner or later end in a stack overflow – derHugo Feb 19 '22 at 12:57
  • I didnt want to leave the co-routine early I just wanted to go back to the options script so I could access the variables to change the line to the end of the options section – RedPandas Feb 19 '22 at 13:22

2 Answers2

1

Your problem is yielding a call to a coroutine function like you are doing here

yield return Talking(text_file, line);

Is more-or-less just going to call the coroutine as a regular function. The behaviour I believe you are looking for is running Talking as a coroutine from within your currently running coroutine.

To do that you would need to do:

yield return StartCoroutine(Talking(text_file, line));

Which will run the function as its own coroutine and wait for it to finish before continuing.

(This is entierly specific to the way unity handles unity-coroutines, and is not generally true for c# IEnumerators of course )

Jay
  • 2,553
  • 3
  • 17
  • 37
-1

An enumerator doesn't do much until it is enumerated. For your yield return Option(...) to work, the consumer would have to check for the enumerator and: enumerate it. I guess that isn't happening. You could perhaps do that in your outer enumerator instead, i.e.

foreach (var val in Option(text_file, line))
{
    yield return val;
}

(Or the same using while (inner.MoveNext()) and inner.Current if you insist on IEnumerator rather than IEnumerable)

As a side note: you should usually prefer generic typed enumerators, i.e. IEnumerator<T> for some specific T.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 1
    This might be true in general but not for Unity [Coroutines](https://docs.unity3d.com/Manual/Coroutines.html) .. OP is already "combining" both `IEnumerator` in `yield return Option(text_file, line);` which yields until the `Option` routine / IEnumerator is finished. For Coroutines the return value is ignored so there is no use in making it generic at all :) `yield return null;` , `yield return true;`, `yield return 42;` .. they all have exactly the same effect in Unity: yield for one frame – derHugo Feb 19 '22 at 12:52