35

Unity3d: Создаем менеджер событий


Всем привет!


Сегодня я не буду писать неинформативные посты про свою игру. Сегодня, наконец-то, немного напишу о технической части. А конкретнее - о "Менеджере Событий".


Рассмотрим ситуацию. Допустим, в интерфейсе разрабатываемой нами/вами игре есть верхняя панель с информацией о валюте игрока и опыте. Эти параметры могут меняться. И меняются они часто.


Как нам постоянно отображать в упомянутой выше панели актуальную информацию об этих параметрах?


* Обновлять информацию каждый кадр в "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;


И т.д.


Думаю, на этом можно закончить.


Спасибо за внимание и успехов всем в ваших начинаниях!

Unity3d: Создаем менеджер событий Gamedev, Unity, Csharp, Gui, Длиннопост

Правила сообщества

ОБЩИЕ ПРАВИЛА:

- Уважайте чужой труд и используйте конструктивную критику

- Не занимайтесь саморекламой, пишите качественные и интересные посты

- Никакой политики


СТОИТ ПУБЛИКОВАТЬ:

- Посты о Вашей игре с историей её разработки и описанием полученного опыта

- Обучающие материалы, туториалы

- Интервью с опытными разработчиками

- Анонсы бесплатных мероприятий для разработчиков и истории их посещения;
- Ваши работы, если Вы художник/композитор и хотите поделиться ими на безвозмездной основе

НЕ СТОИТ ПУБЛИКОВАТЬ:

- Посты, содержащие только вопрос или просьбу помочь
- Посты, содержащие только идею игры

- Посты, единственная цель которых - набор команды для разработки игры

- Посты, не относящиеся к тематике сообщества

Подобные посты по решению администрации могут быть перемещены из сообщества в общую ленту.

ЗАПРЕЩЕНО:

- Публиковать бессодержательные посты с рекламой Вашего проекта (см. следующий пункт), а также все прочие посты, содержащие рекламу/рекламные интеграции

- Выдавать чужой труд за свой

Подобные посты будут перемещены из сообщества в общую ленту, а их авторы по решению администрации могут быть внесены в игнор-лист сообщества.


О РАЗМЕЩЕНИИ ССЫЛОК:

Ссылка на сторонний ресурс, связанный с игрой, допускается только при следующих условиях:

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

- Ссылка должна размещаться непосредственно в начале или конце поста и только один раз

- Cсылка размещается в формате: "Страница игры в Steam: URL"