У меня есть класс "А", который будет отправлять событие "а". Классы, подписавшиеся на событие «а», будут реагировать на это событие. Другие классы могут подписаться на событие «а», ничего не меняя в классе «А»;
Теперь, каков наиболее разумный способ сделать это в единстве? Есть ли какая-то система обмена сообщениями, которая уже может это делать?
Если нет, должен ли я сделать что-то вроде класса EventManager, который будет хранить классы подписчиков в массиве и вызывать их методы?
Вероятно, есть много способов сделать это.
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()
{
//
}
}
Примечание. Набрано на смартфоне, поэтому гарантии нет, но я надеюсь, что идея понятна.
вы можете хранить подписчиков в каждом экземпляре класса A. Кроме того, перед развертыванием собственной системы событий проверьте класс UntiyEvent, который предоставляет хороший редактор для графического редактирования подписчиков (вы также можете расширить его для поддержки ваших собственных типов)