【问题标题】:Unity EventManager that also supports coroutine也支持协程的 Unity EventManager
【发布时间】:2018-04-16 05:54:02
【问题描述】:

我正在寻找支持协程执行的 C# EventManager,例如 this one。换句话说,我希望能够执行以下操作:

EventManager.StartListening("AString", ACoroutine);

我知道我可以将协程包装在一个函数中并使用当前版本的代码,但如果代码本身支持这一点以避免脏代码会更好。

【问题讨论】:

  • 简短回答:我不知道有什么内置的,但没有什么能阻止你自己写一个。但是,我建议只使用@Everts 的建议;当有一个外部系统为其他对象启动协程时,会有很多潜在的问题。
  • 你能给我举个例子吗,这样我就可以理解像这样的外部系统会遇到什么?
  • 当然。想象你有一个类,Foo,派生自 MonoBehaviour,定义了一个 IEnumeratorIEnumerator Bar(),可以作为协程运行。如果Foo.Bar() 内部的任何东西访问了与它所附加的GameObject 相关的东西(比如它的Transform),那么如果GameObjectBar() 仍在运行时被销毁(这是可能的),您将获得异常如果外部系统启动了协程)。如果Foo类本身调用了StartCoroutine(Bar()),那么当对象被销毁时,该协程会自动销毁。

标签: c# events unity3d coroutine


【解决方案1】:

你可以将你的协程包装在一个普通的方法中,这样你就可以使用现有的代码:

private IEnumerator coroutine = null;
void AMethod()
{
     if(this.coroutine != null){ return; } // Already running
     this.coroutine = ACoroutine();
     StartCoroutine(this.coroutine);
}

private IEnumerator ACoroutine()
{
      yield return null;
      this.coroutine = null;
}

void Start()
{
     EventManager.StartListening("AString", AMethod);
}

编辑: 这是支持协程的系统。它必须采用稍微不同的过程(或者至少我没有深入研究它),因此您无需调用该类型的事件,而是创建该类型的列表。这是因为你的 StartCoroutine 不能调用多个委托并且需要迭代。

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EventManager : MonoBehaviour
{
    private Dictionary<string, List<Func<IEnumerator>>> eventDictionary;

    private static EventManager eventManager;

    public static EventManager instance
    {
        get
        {
            if (!eventManager)
            {
                eventManager = FindObjectOfType(typeof(EventManager)) as EventManager;

                if (!eventManager)
                {
                    Debug.LogError("There needs to be one active EventManger script on a GameObject in your scene.");
                }
                else
                {
                    eventManager.Init();
                }
            }
            return eventManager;
        }
    }
    void Init()
    {
        if (eventDictionary == null)
        {
            eventDictionary = new Dictionary<string, List<Func<IEnumerator>>>();
        }
    }
    public void StartListening(string eventName, Func<IEnumerator> listener)
    {
        List<Func<IEnumerator>> thisEvent;
        if (instance.eventDictionary.TryGetValue(eventName, out thisEvent))
        {
            thisEvent.Add(listener);
        }
        else
        {
            instance.eventDictionary.Add(eventName, new List<Func<IEnumerator>>() { listener });
        }
    }

    public void StopListening(string eventName, Func<IEnumerator> listener)
    {
        if (eventManager == null) return;
        List<Func<IEnumerator>> thisEvent;
        if (instance.eventDictionary.TryGetValue(eventName, out thisEvent))
        {
            thisEvent.Remove(listener);
        }
    }

    public void TriggerEvent(string eventName)
    {

        List<Func<IEnumerator>> thisEvent = null;
        if (instance.eventDictionary.TryGetValue(eventName, out thisEvent))
        {
            for (int i = thisEvent.Count -1 ; i >= 0; i--)
            {
                if(thisEvent[i] == null)
                { 
                     thisEvent.RemoveAt(i);
                     continue; 
                }
                StartCoroutine(thisEvent[i]());
            }
        }
    }
}

【讨论】:

  • 正如我在帖子中所写的,我知道我可以使用这种方法。我的问题是在现有代码的情况下是否可以实现对协程的支持。
猜你喜欢
  • 1970-01-01
  • 2010-12-29
  • 1970-01-01
  • 2022-11-14
  • 2010-10-18
  • 2017-05-10
  • 1970-01-01
  • 2017-05-23
  • 2023-03-04
相关资源
最近更新 更多