C# Unity 等待函数被调用

时间:2021-03-26 05:10:01

标签: c# unity3d

我有一个由某个库调用的事件函数。

// Called when an event is received
void OnEvent(EventData data) {
    // something here
}

我需要让协程等到 OnEvent() 函数被调用并接收到 EventData 或超时。

我可以使用自定义的 WaitFor... 函数:

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
}

但我不知道如何实现它。

1 个答案:

答案 0 :(得分:2)

首先,我不会使用协程来实现这一点,我将简单地使用 EventHandler 或直接委托,但是如果您的要求是“创建协程”,我会这样处理:< /p>

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");
    }
}

关键是使用 WaitUntil yield 指令,并使用自定义标志,在这个例子中我使用了一个简单的布尔值,但你可以使用任何你想要的作为委托。

如果要重复使用该标志,请记住再次将其设置为 false!

如果您想更进一步并创建自己的自定义 yield 指令,请尝试使用 CustomYieldInstruction 类,但在底层是类似的。

编辑:可能可以更好地实现,但目前使用 CustomYieldInstruction 的这种近似有效:

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;
    }        
}

像这样使用:

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;
    }
}
相关问题