Всем привет!
Сегодня я не буду писать неинформативные посты про свою игру. Сегодня, наконец-то, немного напишу о технической части. А конкретнее - о "Менеджере Событий".
Рассмотрим ситуацию. Допустим, в интерфейсе разрабатываемой нами/вами игре есть верхняя панель с информацией о валюте игрока и опыте. Эти параметры могут меняться. И меняются они часто.
Как нам постоянно отображать в упомянутой выше панели актуальную информацию об этих параметрах?
* Обновлять информацию каждый кадр в "Update"?
Простой способ, но крайне не желательный с точки зрения оптимизации: "тут" каждый кадр избыточно делаем расчеты/обращения к каким-нибудь параметрам (которые не обновляются каждый кадр), "там" каждый кадр что-то делаем, "сям" и "еще в 30 местах"... Все это копится как снежный ком, а если еще и вычисления не самые простые, то рано или поздно скажется на производительности. Да и в дальнейшем сопровождать такой код может быть не просто...
* В компоненте, где могут измениться параметры денег и/или опыта добавить ссылку на "панель с информацией о валюте и опыте" и уже оттуда вызывать метод обновления отображаемой информации?
С точки зрения производительности этот вариант лучше, потому что каждый кадр не происходит бессмысленное обновление не изменившейся информации. Однако, этот способ не удобен при большом количестве мест, где могут меняться значения валюты и/или опыта.
* Использовать "Менеджер Событий".
На мой взгляд это самый удобный и оптимальный способ. Где бы не происходило изменение значения денег или опыта, следом за изменением сообщаем Менеджеру, что произошло изменение ресурсов. И он уже "сообщает" всем подписавшимся на событие "изменение ресурсов", что событие гм... наступило.
Приведу один из вариантов реализации...
Это наш класс менеджера:
using System;
public static class EventManager
{
#region Actions
public static Action<string> eventOnResourceUpdate;
#endregion
#region Public methods
public static void CallOnResourceUpdate(string _resID)
{
eventOnResourceUpdate?.Invoke(_resID);
}
#endregion
}
Он статичный (модификатор "static"), это позволит использовать его без создания экземпляра. Action<string> eventOnResourceUpdate - это делегат (грубо говоря "событие", на которое мы будем "подписываться" в классе панели с инфой об опыте и валюте). Обратите внимание на <string> - это указан тип аргумента метода/методов, которые могут подписываться на данное событие - что бы не создавать "событие" для каждого ресурса и что бы не обновлять без необходимости информацию обо ВСЕХ ресурсах, метод обновления будет содержать один аргумент - строковое наименование ресурса.
А CallOnResourceUpdate(string _resID) метод, который мы будем вызывать в месте изменения ресурсов (н-р, при списании денег или получении опыта).
Строчка eventOnResourceUpdate?.Invoke(_resID) означает, что если делегат eventOnResourceUpdate НЕ пустой (НЕ равен null), т.е. имеет подписавшиеся методы, то только в таком случае будут вызваны/исполнены все подписанные методы.
Это фрагмент класса панели, отображающей опыт и деньги:
public class ProfileTopPanelController : MonoBehaviour
{
private void OnEnable()
{
EventManager.eventOnResourceUpdate += HandlerOnResourceUpdate;
}
private void OnDisable()
{
EventManager.eventOnResourceUpdate -= HandlerOnResourceUpdate;
}
private void HandlerOnResourceUpdate(string _resID)
{
switch (_resID)
{
case "experience":
UpdateExperience(); //Метод обновления информации об опыте
break;
case "gold":
UpdateCommonCurrency(); //Метод обновления информации о деньгах
break;
}
}
}
В Unity-методах OnEnable и OnDisable (обращаю внимание новичков на то, что очень важно соблюдать регистр написания этих методов, иначе Unity не будет использовать их, т.к. рефлексия их не найдет) мы соответственно подписываемся и отписываемся от делегата ("события обновления ресурсов") eventOnResourceUpdate. После этого все время, что панель активна, при вызове метода CallOnResourceUpdate в нашем Менеджере, панель будет выполнять код метода HandlerOnResourceUpdate с аргументом - идентификатором ресурса.
Если необходимо, что бы код выполнялся и во время временной "деактивации" панели (причины могут быть разные...), то отписку от события переносим в метод OnDestroy.
А это фрагмент кода в том месте, где идет изменение параметров денег/опыта:
//...
//Здесь код изменения кол-ва ресурса
//...
EventManager.CallOnResourceUpdate(_id); //А здесь идет вызов события изменения ресурсов, "_id" - это строковый идентификатор ресурса
Такое несложное решение, конечно же, можно использовать не только для "отслеживания" изменения ресурсов в вашей игре. Можно добавить любые события, которые вам необходимы. Нужно событие для сохранения? Оно может выглядеть следующим образом public static Action eventOnSave; какой-нибудь NPC получил новый уровень? Пожалуйста - public static Action<object> eventNpcNewLevel;
И т.д.
Думаю, на этом можно закончить.
Спасибо за внимание и успехов всем в ваших начинаниях!