Що слід враховувати при проектуванні системи Event Manager?


9

Я підходив до основ ігрового двигуна Java, і дойшов до того, коли я готовий додати в систему Event Manager.

Я теоретично знаю, що повинен робити Менеджер подій: дозволяти об’єктам "реєструватися" для певних подій, і щоразу, коли Менеджер подій отримує повідомлення про подію, транслює подію "зареєстрованим" слухачам. Те, про що я натрапив - це як почати його реалізовувати.

Мені в Інтернеті нічого не вдалося знайти про те, як запровадити систему подій з нуля, тому я шукаю інформацію про те, які найкращі практики в цьому випадку - що я повинен, а що не повинен робити.

Наприклад, чи дійсно потрібно, щоб кожен з моїх ігрових об’єктів мав EventManagerполе? Оскільки всі мої ігрові об'єкти успадковуються від одного, абстрактного батьківського класу, я думаю, я повинен мати можливість використовувати статичну довідку, щоб було лише один екземпляр диспетчера подій, розділений між усіма ігровими об'єктами. Я роблю щось подібне, з Applet, що я використовую для візуалізації кожного об'єкта.

Я думаю, мені доведеться підтримувати якусь колекцію для кожної можливої ​​передплаченої події - додавання та видалення ігрових об’єктів зі списку, якщо потрібно. Я думаю , що це повинно бути можливо зробити чергу подій , які повинні бути мовлення, в цьому випадку я міг би просто додати «EventManager.Update ()» в основний цикл гри, і є Update()спосіб транслювати події , які відбулися в кінці кожного кадру. Нарешті, кожен об'єкт мав би HandleEvent(Event e)метод, який потім міг би аналізувати та відповідати відповідним чином.


Чи звучить це як відповідний напрямок до впровадження такої системи, чи я відхиляюсь від шляху та / або пропускаю щось цілком очевидне?


2
gamedev.stackexchange.com/questions/7718/… Це попередній Q / AI, який ви давали раніше, який може допомогти вам розпочати роботу.
Джеймс

@James Ah - схоже на гарне посилання. Дякую! Я думаю, що я пропустив це раніше.
Ворон Сонник

4
Деякі додаткові підказки: вирішіть, чи повинні насправді деякі події набирати чинності негайно, а не в кінці кадру, особливо якщо обробник подій викликає додаткові події; подумайте, що станеться, коли ви отримаєте петлі подій; якщо ви йдете з чергою, можливо, вам знадобиться система пріоритетів або спосіб обійти чергу.
sam hocevar

Відповіді:


6

Це може бути так просто, як ви хочете.

for each object in the subscriber list:
    object.notify(this event) // (or 'HandleEvent' if you prefer)

Не намагайтеся розробити те, що повинен робити менеджер подій - розробляйте те, що вам потрібно. Решта має випливати звідти, або, принаймні, пропонувати деякі конкретніші запитання.


3
+1 для "Не намагайся розробити те, що має робити X" - розроби, що потрібно для цього. " Насправді, взагалі не додайте диспетчера подій, поки не відчуєте, що вам потрібен якийсь розв'язаний, але централізований спосіб виклику функцій.

@JoeWreschnig О боже, так =) "Випрацюйте, що вам потрібно для цього" Це один з трьох найкращих порад, який будь-який розробник повинен прийняти до душі.
Патрік Х'юз

Спочатку я хотів не погодитися з вашим другим реченням щодо не додавання менеджера подій, оскільки більшість ігор може скористатися розв'язаним ще централізованим способом виклику функцій, але потім я подумав, скільки маленьких ігор я зробив, що не мати будь-який менеджер подій. так, так
поштовх

3

Три основні методи, яким потрібна система подій, це метод addListener (), метод removeListener () та метод dispatchEvent (). Тобто, об'єкти методів використовують для реєстрації події, методи, які об’єкти використовують для нереєстрації, і метод фактичної трансляції події всім слухачам. Все інше - підлив.

Як зазначаєте, вам точно знадобиться якась структура даних, щоб відстежувати зареєстрованих слухачів. Найпростішим підходом буде асоціативний масив (словник або об’єкт у JavaScript), який асоціює вектор (або просто масив залежно від мови) із подією. Цей вектор - це список усіх зареєстрованих слухачів; додайте слухачів до списку або видаліть їх методами add / removeListener ().

Для трансляції події в dispatchEvent () це може бути так само просто, як прокручування вектора. Ви можете додати більше складності диспетчеризації, сортуючи пріоритет подій чи будь-що інше, але не хвилюйтеся з цього приводу, поки не знадобиться. У багатьох випадках він вам не знадобиться.

Диспетчер Event () має невеликий нюанс, коли ви враховуєте, які дані передавати разом із подією. На самому базовому рівні ви не можете передавати додаткові дані; все, що слухач повинен знати, це те, що відбулася подія. Однак у більшості подій є додаткові дані, які йдуть разом із ними (наприклад, де відбулася подія), щоб вам захотілося, щоб dispatchEvent () приймав і передавав деякі параметри.

Наприклад, чи дійсно потрібно, щоб кожен з моїх GameObjects мав поле "EventManagner"? Оскільки всі мої GameObjects успадковуються від одного, абстрактного батьківського класу, я думаю, я повинен мати можливість використовувати статичну довідку, щоб було лише один екземпляр EventManager, який розподіляється між усіма ігровими об'єктами.

Існує багато способів дати всім ігровим об'єктам посилання на клас EventManager. Статичний довідник, безумовно, є одним із способів; інша - з Сінглтоном. Обидва ці підходи, однак, досить негнучкі, тому більшість людей тут рекомендують або локатор обслуговування, або ін'єкцію залежності. Я робив ін’єкцію залежності; це означає окреме поле EventManager для кожного об'єкта, чого ви, схоже, хочете уникати, але я не впевнений, чому це проблема. Це не так, як багато зберігати накладні витрати, щоб зберігати купу покажчиків.


так, я вперше зрозумів та застосував введення залежності для об’єкта EventDispatcher. Як тільки я потрапив під пояс, я свербіла, щоб перетворити багато речей з таким малюнком.
поштовх

0

ВІДХОДЖЕННЯ

Я не програміст Java, але я написав статтю, в якій пояснював, як створити систему подій у C89, одній з найпростіших мов (IMHO), перевірте це

https://prdeving.wordpress.com/2017/04/03/event-driven-programming-with-c-89/

Основи обробки подій досить прості.

  • зареєструвати подію за допомогою зворотного дзвінка
  • тригер події
  • прокрутіть слухачів, щоб побачити, чи є відповідність
  • обробник вогню, якщо його знайдено
  • повторити

Знаючи це (але не знаючи, як це реалізувати в Java), легко зрозуміти, що вам потрібні деякі обробники (функції для обробки подій) і додати їх до масиву (з покажчиками, на C), поєднаного з назвою події. Після запуску події ви зберігаєте ім'я викликаної події та його аргументи у стеці, це називається пулом подій.

Тоді у вас є дайджест подій (простий цикл), який вискакує першу подію в цьому стеку, намагається знайти обробник для нього, і якщо є такий, запускає його з парами.

Звичайно, цей дайджест подій можна запускати коли завгодно, наприклад, один раз на кадр після виклику Update()функції.


-2

Для поля EventManager використовуйте статичну змінну. Сінглтон для EventManager також буде чудовою ідеєю.

Ваш підхід звучить добре, але не забудьте зробити його безпечним для потоків.

Добре виконувати IO-Events до або після "GameEvent", тому в одному кадрі кожен "GameEvent" має справу з тими ж даними.


"Зберегти нитку"? Хммм
U62

-1 для абсолютно непотрібної та необгрунтованої навігаторної однозначності.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.