Я разбираюсь с основами игрового движка Java и достиг той точки, когда я готов добавить систему Event Manager.
Теоретически я знаю, что должен делать Менеджер событий: разрешать объектам «регистрироваться» для определенных событий, и всякий раз, когда Менеджер событий получает уведомление о событии, передает событие «зарегистрированным» слушателям. То, что я поставил в тупик, это как начать это реализовывать.
Я не смог ничего найти в Интернете о внедрении системы событий с нуля, поэтому я ищу информацию о том, каковы лучшие практики в этом случае - что я должен и не должен делать.
Например, действительно ли необходимо, чтобы у каждого из моих игровых объектов было EventManager
поле? Поскольку все мои игровые объекты наследуются от одного абстрактного родительского класса, я думаю, что я должен иметь возможность использовать статическую ссылку, чтобы был только один экземпляр диспетчера событий, общий для всех игровых объектов. Я делаю нечто похожее с апплетом, который уже использую для рендеринга каждого объекта.
Полагаю, мне нужно было бы поддерживать какую-то коллекцию для каждого возможного подписанного события - добавлять и удалять игровые объекты из списка по мере необходимости. Я думаю, что должна быть возможность создать очередь событий, которые должны быть переданы, и в этом случае я мог бы просто добавить EventManager.Update () в основной цикл игры, и чтобы Update()
метод транслировал события, которые произошли в конце каждого кадра. Наконец, у каждого объекта должен быть HandleEvent(Event e)
метод, который они могли бы затем проанализировать и ответить соответствующим образом.
Похоже ли это на правильное направление реализации такой системы, или я не в курсе и / или упускаю что-то совершенно очевидное?
Ответы:
Это может быть так просто, как вы хотите.
Не пытайтесь понять, что должен делать менеджер событий - определите, что вам нужно. Остальное должно следовать оттуда или, по крайней мере, должно предлагать более конкретные вопросы.
источник
Три основных метода, которые необходимы системе событий, - это метод addListener (), метод removeListener () и метод dispatchEvent (). То есть объекты метода используют для регистрации события, объекты метода используют для отмены регистрации и метод для фактической трансляции события всем слушателям. Все остальное - соус.
Как вы заметили, вам, безусловно, понадобится какая-то структура данных для отслеживания зарегистрированных слушателей. Самый простой подход - это ассоциативный массив (словарь или объект в JavaScript), который связывает вектор (или просто массив в зависимости от языка) с событием. Этот вектор является списком всех зарегистрированных слушателей; добавить слушателей в список или удалить их в методах add / removeListener ().
Для трансляции события в dispatchEvent () это может быть так же просто, как пройти через вектор. Вы можете добавить усложнение диспетчеризации, отсортировав приоритет событий или чего-то еще, но не беспокойтесь об этом, пока вам это не понадобится. Во многих случаях вам это не понадобится.
В dispatchEvent () есть небольшой нюанс, когда вы рассматриваете, какие данные передать вместе с событием. На самом базовом уровне вы можете не передавать никаких дополнительных данных; Все, что слушатель должен знать, - это то, что произошло событие. Однако большинство событий имеют дополнительные данные, которые идут вместе с ними (например, где произошло событие), и вы захотите, чтобы dispatchEvent () принимал и передавал некоторые параметры.
Есть много способов дать всем вашим игровым объектам ссылку на класс EventManager. Статическая ссылка, безусловно, является одним из способов; другой синглтон. Однако оба эти подхода довольно негибкие, поэтому большинство людей здесь рекомендуют либо указатель службы, либо внедрение зависимости. Я делал инъекцию зависимости; это означает отдельное поле EventManager для каждого объекта, чего вы, похоже, хотите избежать, но я не уверен, почему это проблема. Это не значит, что хранение множества указателей слишком дорого.
источник
Основы обработки событий довольно просты.
Зная это (но не зная, как реализовать это в Java), легко понять, что вам нужны некоторые обработчики (функции для обработки событий) и добавить их в массив (с указателями в C), связанный с именем события. Как только вы запускаете событие, вы сохраняете имя сработавшего события и его аргументы в стеке, это называется пулом событий.
Затем у вас есть дайджест события (простой цикл), который вставляет первое событие в этот стек, пытается найти для него обработчик и, если есть, запускает его с параметрами.
Конечно, этот дайджест события может быть запущен в любое время, например, один раз за кадр после вызова вашей
Update()
функции.источник
Для поля EventManager используйте статическую переменную. Синглтон для EventManager тоже будет отличной идеей.
Ваш подход звучит хорошо, но не забудьте сделать его потокобезопасным.
Хорошо выполнять IO-события до или после «GameEvent», поэтому в одном кадре каждый «GameEvent» обрабатывает одни и те же данные.
источник