[Программирование, Проектирование и рефакторинг, Разработка игр, Unity] Подпишись, чтобы не пропустить — События

Автор Сообщение
news_bot ®

Стаж: 6 лет 3 месяца
Сообщений: 27286

Создавать темы news_bot ® написал(а)
16-Июн-2021 22:31

Событийно-ориентированный подход к разработке позволяет естественным изолировать реализацию бизнес-логики приложения от пользовательского интерфейса. Как в большей степени Unity-разработчик, я буду демонстрировать все именно в контексте геймдева. В прошлой статье я показал, как конечные автоматы позволяют организовать бизнес-логику в виде системы состояний со строго обозначенным поведением. Сегодня мне бы хотелось уделить внимание тому, как именно автомат должен взаимодействовать с игровыми объектами и управлять состоянием сцены.В примерах в статье про автоматы я использовал следующую конструкцию:
Game.Event.Invoke("joystick_updated", input);
По структуре вызова функции можно понять, что есть некоторый статический класс Game, предоставляющий глобальный доступ к своим полям, что очень удобно при небольших размерах проекта. Вот часть его содержимого:
public static class Game
{
    public static FSM Fsm = new FSM();
    public static EventManager Event = new EventManager();
    public static ObservableData Data = new ObservableData();
...
В этих примерах можно увидеть некоторые вольности в деталях реализации. При масштабировании проекта, например, придется отказаться от статического контекста и на основе класса Game реализовать компоненты, назовем их претенциозно MonoBehaviourPro с подобной структурой для сложных подсистем, и передавать ее в качестве контекста автомату и компонентам этих подсистем. Я намеренно сглаживаю эти углы для большей наглядности примера. Сегодня мы рассмотрим класс с многострадальным названием EventManager, так как он является зависимостью ObservableData и без него мы не сможем двинуться дальше. По ссылке можно увидеть полную реализацию класса EventManager, принцип его работы предельно прост. Мы храним список делегатов c произвольной сигнатурой, подписанных на события со строковым ключом. Важно, что мы работаем с Generic-структурой, поэтому следует помнить о Type safety. Тип аргумента при отправке события должен соответствовать сигнатурам функций, подписанных на него. Также, можно заметить, что EventManager отдельно хранит binds и binds_global и имеет отдельный интерфейс для работы с ними. Это реализация, специфичная для Unity. Дело в том, что там существует система сцен, позволяющая подгружать или выгружать сцены и объекты. И разница между этими двумя словарями в том, что первый очищается при выгрузке сцены. В идеальном мире мы всегда подписываем объект в Awake и отписываем его в OnDestroy. В таком случае можно было бы обойтись одним binds, не очищая его никогда. Каждый объект подписывается и отписывается в рамках своего жизненного цикла и разве что при переходе между сценами происходило бы немного лишней работы над поштучным отписыванием выгружаемых объектов. Но такой подход не прощает ошибок, выгруженный подписчик в лучшем случае сразу сломает вызов делегата и будет найдена, а в худшем - станет причиной утечки памяти. Так что, в качестве "защиты от дурака" лучше при переходе явно отписывать все, что не было обозначено как Global.Итак, интерфейс EventManager cводится к 5 методам:
public void Bind<T>(string name, Action<T> ev)
        public void BindGlobal<T>(string name, Action<T> ev)
        public void Unbind<T>(string name, Action<T> ev)
        public void UnbindGlobal<T>(string name, Action<T> ev)
        public void Bind(string name, Action ev)
        public void BindGlobal(string name, Action ev)
        public void Unbind(string name, Action ev)
        public void UnbindGlobal(string name, Action ev)
        public void Invoke<T>(string name, T arg)
        public void Invoke(string name)
Мы можем подписываться на события и отправлять их. И все это с аргументом произвольного типа. В примере из статьи про FSM мы передавали ввод с джойстика в автомат и, если состояние предусматривает такую возможность, передавали в EventManager событие изменения положения джойстика , на которое может подписаться компонент, управляющий положением игрока(Или потомок MonoBehaviourPro, какой нибудь PlayerController, который передаст информацию о вводе в свой автомат, и если игрок в состоянии SPlayerDriving , будет передавать ввод с джойстика уже автомобилю, за рулем которого он сидит, а если в SPlayerClimbing, джойстик будет двигать игрока перпендикулярно нормали плоскости, по которой он движется, с соответствующей анимацией. Но это уже более сложные примеры, не будем на этом задерживаться). Или же, на входе в состояние игры SWin мы можем отправить событие level_done, а на него подписать анимацию экрана победы, конфетти, и чего там еще ваш ГД придумает.Некоторые события, не влияющие на игровой процесс, такие как включение-выключение звука, вполне можно обрабатывать в обход автомата, отправляя событие напрямую с кнопки, и принимая его классом-оберткой PlayerPrefs, как бы он ни был устроен. Тут я призываю вас руководствоваться здравым смыслом и собственным чувством прекрасного. Таким образом, автомат в процессе своей работы может отправлять события подписавшимся на них объектам через EventManager. В следующей статье я расскажу о возможностях, предоставляемых классом ObservableData в связке с описанными инструментами.Эта статья - вторая в серии:
- Разделяй и властвуй — Использование FSM в Unity
- Подпишись, чтобы не пропустить — События
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_programmirovanie (Программирование), #_proektirovanie_i_refaktoring (Проектирование и рефакторинг), #_razrabotka_igr (Разработка игр), #_unity, #_shablony_proektirovanija (шаблоны проектирования), #_unity3d, #_gamedev, #_arhitektura_prilozhenij (архитектура приложений), #_programmirovanie (
Программирование
)
, #_proektirovanie_i_refaktoring (
Проектирование и рефакторинг
)
, #_razrabotka_igr (
Разработка игр
)
, #_unity
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 22-Май 04:41
Часовой пояс: UTC + 5