IEnumerator Events

Ok so I am at my wit’s end here. Basically I have a turn-based game where I need to (on an event firing) wait for user-input, player animation, etc. I thought I had this on lock until I actually ran a test and realized only the last event associated with any eventhandler fires. Here is an example of what I’m talking about:

delegate IEnumeratorTestHandler(MonoBehaviour c);
event TestHandler MyTest;

void Start()
{
MyTest+= TestA;
MyTest+= TestB;
StartCoroutine(Mooo());
}
IEnumerator Mooo()
{
MyTest?.Invoke(this);
yield break;
}
IEnumerator TestA(MonoBehaviour c) { Debug.Log(“TEST A”); yield break; }
IEnumerator TestB(MonoBehaviour c) { Debug.Log(“TEST B”); yield break; }

The output prints only “TEST B”. How on earth do I yield an event handler?

Any and all help is appreciated.

Thank you!

Check code formatting please, first post in forum.

Also, neither Test A or Test B should print, as far as I can tell.

Your one Invoke(this) generates IEnumerators for all events delegates that you simply discard right there.

You don’t store them, call them, .MoveNext() them, or hand them back with yield, or call StartCoroutine().

Remember if you just call Mooo() and do nothing else, none of your code actually runs. You’d have to call Mooo().MoveNext() to invoke it once, then it would just be pointless anyway.

Same thing applies to the IEnumerators returned by your events: something has to pump them to get any actual code running. In the case of StartCoroutine it is Unity doing the pumping for you, by agreement based on what you return (such as wait, waitfor, null, etc.)

In any case, I don’t think you can receive collections of IEnumerators back like that from an event and do anything meaningfully. If that’s what you need, just make a mechanism that lets you add coroutines you want to run and have it service the event explicitly, via one single subscribe. For one you’ll be able to control the details of its behavior better (and it will get complicated fast!), and for two, we can sorta reason about how to do that already.

So just to expand a little bit on what Kurt said, which was all valid, if you have an event based on a delegate that has a return value, you can invoke the event and get a return value from it. Unfortunately the return value you get will only be that of the LAST delegate in the event. That’s why no matter what you do you are only getting “TEST B” to print.

You’ll have to use something other than an event for this to work. Maybe something like this?

public class test : MonoBehaviour
{
    public delegate IEnumerator TestHandler(MonoBehaviour c);
    List<TestHandler> listeners = new List<TestHandler>();

    void Start() {
        print("hi");
        AddListener(TestA);
        AddListener(TestB);
        StartCoroutine(Mooo());
    }

    public void AddListener(TestHandler listener) {
        listeners.Add(listener);
    }

    IEnumerator Mooo() {
        foreach (var listener in listeners) {
            yield return listener(this);
        }
    }
    IEnumerator TestA(MonoBehaviour c) {
        Debug.Log("TEST A");
        yield return null;
    }
    IEnumerator TestB(MonoBehaviour c) {
        Debug.Log("TEST B");
        yield return null;
    }
}