Как реализовать отправитель событий - приемник событий игровых объектов в единстве? - PullRequest
0 голосов
/ 27 мая 2019

У меня есть класс "A", который отправит событие "a". Классы, которые подписываются на событие «а», будут реагировать на это событие. Другие классы могут подписаться на событие «а», не меняя ничего в классе «А»;

Теперь, какой самый разумный способ сделать это в единстве? Есть ли какая-нибудь система обмена сообщениями, которая уже может это сделать?

Если нет, я должен создать что-то вроде класса EventManager, который будет хранить классы подписчиков в массиве и вызывать их методы?

1 Ответ

3 голосов
/ 27 мая 2019

Вероятно, есть много способов сделать это.

Публичный статический список

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

Global EventHandler

Или, если вы предпочитаете инкапсуляцию, используйте, как вы упомянули, глобальный обработчик событий для всех 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();
    }
}

Теперь вы не можете легко добавлять обратные вызовы к этому событию в Инспекторе Unity, перетаскивая в GameObjects / Components и выбирая метод для вызова. (Точно то же самое используется для события 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()
    {
        //
    }
}

Примечание: напечатано на смартфоне, поэтому никаких гарантий, но я надеюсь, что идея проясняется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...