Как реализовать отправителя событий - игровые объекты получателя событий в единстве?

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

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

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

вы можете хранить подписчиков в каждом экземпляре класса A. Кроме того, перед развертыванием собственной системы событий проверьте класс UntiyEvent, который предоставляет хороший редактор для графического редактирования подписчиков (вы также можете расширить его для поддержки ваших собственных типов)

zambari 27.05.2019 12:50
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
1 442
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

Общедоступный статический список

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

а в А есть

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()
    {
        //
    }
}

Примечание. Набрано на смартфоне, поэтому гарантии нет, но я надеюсь, что идея понятна.

Другие вопросы по теме