簡體   English   中英

等待 Unity Coroutine 中的事件?

[英]Waiting for event inside Unity Coroutine?

所以我有一個 Unity 協程方法,其中有一些對象。 這些對象表示從某處服務器收集的值,並在准備就緒時發送Updated事件。

我想知道最好的方法是在 Unity 的協程中等待更新所有值。

public IEnumerator DoStuff()
{
    foreach(var val in _updateableValues)
    {
        if (val.Value != null) continue;
        else **wait for val.Updated to be fired then continue**
    }
    //... here I do stuff with all the values
    // I use the WWW class here, so that's why it's a coroutine
}

做這樣的事情最好的方法是什么?

謝謝!

沒有內置的直接方法來等待事件本身,但您可以使用同步嵌套協程來等待事件設置的標志:

//Flag
bool eventHappened;

//Event subscriber that sets the flag
void OnEvent(){
    eventHappened=true;
}

//Coroutine that waits until the flag is set
IEnumerator WaitForEvent() {
    yield return new WaitUntil(eventHappened);
    eventHappened=false;
}

//Main coroutine, that stops and waits somewhere within it's execution
IEnumerator MainCoroutine(){
   //Other stuff...
   yield return StartCoroutine(WaitForEvent());
   //Oher stuff...
}

考慮到這一點,創建一個等待UnityEvent的通用協程很容易:

private IEnumerator WaitUntilEvent(UnityEvent unityEvent) {
    var trigger = false;
    Action action = () => trigger = true;
    unityEvent.AddListener(action.Invoke);
    yield return new WaitUntil(()=>trigger);
    unityEvent.RemoveListener(action.Invoke);
}

我認為更好的方法是每幀檢查服務器,而不是不假思索地等待一段時間。

public IEnumerator DoStuff()
{
     /* wait until we have the value we want */
     while( value != desiredValue)
     yield return null
     //after this loop, start the real processing
}

這是我的小修復。

為什么有一個包含一行代碼的協程? 我直接在需要的地方使用 WaitUntil。 不過我發現,WaitUntil 不需要布爾值,但需要一個布爾謂詞函數 - 所以我在下面的示例中提供了這個。

該示例是來自游戲的真實運行代碼。 它在第一個場景中運行,在我開始之前開始播放音樂 - 稍微長一點 - 加載其他東西。

     //         
     public class AudioSceneInitializer : MonoBehaviour
    {
        [SerializeField] private GlobalEventsSO globalEvents;
        //globalEvents is a scriptable object that - in my case - holds all events in the game
        [SerializeField] private AudioManager audioManager;
        //The audio manager which in my case will raise the audio ready event
        [SerializeField] public GameObject audioGO;// contains AudioSources used by AudioManager
        private bool audioReady = false;

        // Start is called before the first frame update
        IEnumerator Start()
        {
            if (audioManager != null)
            //better check, if we don't produce the event, we wait forever
            {
                //subscribe to event
                globalEvents.audioManagerReadyEvent += OnAudioReady;
                //do something to raise the event - else we wait forever
                audioManager.onInitialization(this);//"this" needed to hand over the audioGO to the AudioManager
                //  waits until the flag is set;
                yield return new WaitUntil(IsAudioReady);
              
            }
            //now that we have music playing, we load the actual game 
            SceneManager.LoadSceneAsync(1, LoadSceneMode.Additive);
        }  
        //Event subscriber that sets the flag
        void OnAudioReady()
        {
            //unsubscribing, if - as in my case - it happens only once in the game
            globalEvents.audioManagerReadyEvent -= OnAudioReady;
            audioReady = true;
        }
        //predicate function that WaitUntil expects
        private bool IsAudioReady()
        {
            return audioReady;
        }
        public void OnDisable()
        {
            audioManager.onCleanup();
        }
    }

自旋鎖是一種解決方案,但不是 CPU 非常溫和的解決方案。 在自旋鎖中,您只需等待變量具有特定值,否則會休眠幾毫秒。

public IEnumerator DoStuff()
{
     /* wait until we have the value we want */
     while( value != desiredValue)
         yield return new WaitForSeconds(0.001f);
    //after this loop, start the real processing
}

也許您可能想考慮重構您的代碼,以便不需要自旋鎖,但可以實現更多基於中斷/事件的方法。 這意味着,如果您更新了一個值並且在它發生之后必須發生某些事情,請在更改該值后直接啟動它。 在 C# 中,甚至有一個用於該設計模式的接口INotifyPropertyChanged (請參閱MSDN ),但您也可以輕松地自己設計它,例如,通過在特定值更改時觸發事件。 如果你想要一個比自旋鎖更好的解決方案,我們需要更多關於你到底想在這里做出什么反應的信息,但這應該會給你一些想法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM