Tengo una función de evento que es llamada por alguna biblioteca.
// Called when an event is received void OnEvent(EventData data) { // something here }Necesito hacer que la corrutina espere hasta que se llame a la función OnEvent() y reciba los datos del evento o el tiempo de espera.
Podría usar una función WaitFor... personalizada como esa:
IEnumerable WaitForEventOrTimeout(int timeout, outc EventData eventData) { // Something } IEnumerable coroutine() { EventData eventData; yield return WaitForEventOrTimeout(4 /*timeout in 4 seconds if nothing received*/, eventData); if (evnt == null) { // Didn't receive event because timeout happened, handle that } // Do stuff with received event }Pero no sé cómo implementarlo.
En primer lugar, no usaría una rutina para lograr eso, simplemente usaré un EventHandler o un delegado directo, pero si su requerimiento es "hacer una rutina", lo abordaré así:
using System.Collections; using UnityEngine; public class SOExample: MonoBehaviour { public bool OnEventCalled = false; private void Start() { //Starts coroutine to wait until OnEvent StartCoroutine(MyOwnCoroutine()); } public void OnLibraryEvent(string data) { Debug.Log("OnLibraryEvent"); OnEventCalled = true; } private IEnumerator MyOwnCoroutine() { Debug.Log("Waiting"); yield return new WaitUntil(() => OnEventCalled); Debug.Log("Do stuff with received event"); } }La clave es usar la instrucción de rendimiento WaitUntil y usar un indicador personalizado, en este ejemplo he usado un booleano simple, pero puede usar lo que quiera como delegado.
¡Recuerde volver a establecer en falso la bandera si desea reutilizarla!
Si desea ir más allá y crear su propia instrucción de rendimiento personalizada, intente con la clase CustomYieldInstruction , pero es similar bajo el capó.
EDITAR : probablemente se pueda implementar mejor, pero esta aproximación con CustomYieldInstruction actualmente funciona:
public class WaitForEventOrTimeout : CustomYieldInstruction { //used to call StartCoroutine inside this class private MonoBehaviour mono = null; private Func<bool> checkIfEventIsTriggered = null; private float waitingTime = 0; private bool timeoutTriggered = false; //this will be checked continously while returns true public override bool keepWaiting { get { return !timeoutTriggered && !checkIfEventIsTriggered(); } } //Constructor called when "new" public WaitForEventOrTimeout(MonoBehaviour mono, Func<bool> checkIfEventIsTriggered, float waitingTime) { this.mono = mono; this.waitingTime = waitingTime; this.checkIfEventIsTriggered = checkIfEventIsTriggered; //Starts countdown to timeout mono.StartCoroutine(WaitForTimeout()); } private IEnumerator WaitForTimeout() { yield return new WaitForSeconds(waitingTime); timeoutTriggered = true; } }Úsalo como:
using System; using System.Collections; using UnityEngine; public class SOO : MonoBehaviour { private bool _onEvent = false; public bool OnEvent() => _onEvent; private void Start() { //Starts coroutine to wait until OnWaitForEventOrTimeout StartCoroutine(MyOwnCoroutine()); } public void OnLibraryEvent() { //When LibraryEvent is called, set the flag to true _onEvent = true; } private IEnumerator MyOwnCoroutine() { Debug.Log("Waiting"); yield return new WaitForEventOrTimeout(this, OnEvent, 4); Debug.Log("Do stuff with received event"); //Reset flag _onEvent = false; } }