首页 > 解决方案 > 如何统一实现事件发送者 - 事件接收者游戏对象?

问题描述

我有“A”类,它将发送事件“a”。订阅事件“a”的类将对此事件作出反应。其他类可以订阅事件“a”,而无需更改“A”类中的任何内容;

现在,团结起来最合理的方法是什么?是否有一些消息传递系统已经可以做到这一点?

如果不是,我是否应该制作类似 EventManager 类的东西,它将订阅者类存储在数组中并调用它们的方法?

标签: c#unity3d

解决方案


可能有很多方法可以做到这一点。

公共静态列表

public class A : MonoBehaviour
{
    public static List<A> AvailableAs = new List<A>();

    private void Awake()
    {
        if(!AvailableAs.Contains(this)) AvailableAs.Add(this);
    }

    private void OnDestroy()
    {
        if(AvailableAs.Contains(this)) AvailableAs.Remove(this);
    }

    public void SomePublicMethod()
    {
        // magic
    }
}

并使用它,例如

public class B : MonoBehaviour
{
    // run the method on all currently registered A instances
    public void DoIt()
    {
        foreach(var a in A.AvailableAs)
        {
            a.SomePublicMethod();
        }
    }
}

全局事件处理程序

或者,如果您更愿意进行封装,就像您提到的所有 A 一样的全局事件处理程序

namespace ANamespace
{
    public static class AEventHandler
    {
        internal static event Action OnInvokeA;

        public static void InvokeAEvent()
        {
            if(OnInvokeA != null) OnInvokeA.Invoke();
        }
    }
}

并且在 A 中有

namespace ANamespace
{
    public class A : MonoBehaviour { 

        private void Awake()
        {
            // it is save to remove a callback first even 
            // if it was not added yet. This makes sure it is
            // added only once always
            AEventHandler.OnIvokeA -= SomePrivateMethod;
            AEventHandler.OnIvokeA += SomePrivateMethod;
        }

        private void OnDestroy()
        {
            AEventHandler.OnIvokeA -= SomePrivateMethod;
        }

        private void SomePrivateMethod()
        {
            // magic
        }

    }  
}

现在在B你宁愿简单地做

// invoke the event and whoever is added as listener will do 
// whatever he registered
// in this case all A instances execute their method
AEventHandler.InvokeAEvent();

团结事件

但是,如果您只有一个引发事件的类A并且您希望其他人对其做出反应,只需使用UnityEvent类似

public class A : MonoBehaviour
{
    public UnityEvent OnSomethingHappened = new UnityEvent();

    private void SomeMethodIWillRun()
    {
        //...
        OnSomethingHappened.Invoke();
    }
}

现在,您可以通过拖入 GameObjects/Components 并选择要调用的方法轻松地在 Unity Inspector 中为该事件添加回调。onClick(顺便说一句,组件的事件使用完全相同的东西Button。;))

你仍然可以在运行时通过脚本添加回调,比如

public class B : MonoBehaviour
{
    public A referenceToA;

    private void Start()
    {
        referenceToA.OnSomethingHappened.AddCallback(OnASomethingHappened);
    }

    private void OnDestroy()
    {
        referenceToA.OnSomethingHappened.RemoveCallback(OnASomethingHappened)
    }

    private void OnASomethingHappened()
    {
        //
    }
}

注意:在智能手机上打字,所以没有保修,但我希望这个想法很清楚。


推荐阅读