Чи можу я зійти з розуму з поводниками подій? Чи я йду «неправильним шляхом» зі своїм дизайном?


12

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

В даний час мій ігровий двигун виконує базовий спрайт-рендерінг за допомогою панорамної накладної камери. Моя конструкція виглядає приблизно так:

SceneHandler

Містить список класів, які реалізують інтерфейс SceneListener (на даний момент лише Sprites). Виклики render () один раз за галочку та надсилає onCameraUpdate (); повідомлення для слухачів сцени.

InputHandler

Опитує вхід один раз за галочку та надсилає просте повідомлення "onKeyPress" на InputListeners. У мене є Camera InputListener, який містить примірник SceneHandler і запускає updateCamera (); події на основі того, що є вхідним даних.

AgentHandler

Викликає дії за замовчуванням для будь-яких агентів (AI) один раз за галочку та перевірятиме стек для будь-яких нових подій, які реєструються, надсилаючи їх конкретним Агентам у міру необхідності.

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

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

Я розумію, що в деяких випадках, таких як мій InputHandler та SceneHandler, це дуже специфічні типи подій. Велика частина мого ігрового коду не піклується про введення, а велика частина не піклується про оновлення, які відбуваються виключно під час відображення сцени. Тому я вважаю, що моя ізоляція цих систем виправдана. Однак я задаю це питання, зокрема, підходячи до подій типу логічної гри.

Відповіді:


21

Дизайн на основі подій здебільшого включає реалізацію схеми дизайну Reactor .

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

Перша і найважливіша проблема полягає в тому, що обробники повинні швидко повернутися , як добре знає кожен, хто виконував деякі серійні роботи на основі GUI та фреймворків.

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

У цих випадках можна виділити дві ситуації (не обов'язково взаємовиключні):

Складні обов'язки, пов'язані з подіями, і складні обов'язки, пов'язані з подіями .

Складні обов'язки, пов'язані з подіями:

У першому випадку ви об'єднали занадто багато обов'язків у однокомпонентний обробник : занадто багато дій вживається у відповідь на подію або є, наприклад, запущені синхронізації.

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

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

Складні обов'язки, пов'язані з подіями:

Другий випадок трапляється, коли в дії, яку потрібно здійснити після події, є суттєва складність : вам потрібно обчислити число, наприклад, після події, наприклад.

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

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

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

Коли обробнику потрібно розпочати довгу дію, він інкапсулює цю дію в блок роботи, який повинен бути поміщений у чергу завдань. Ця інкапсульована дія повинна мати значення, щоб викликати події в реакторі. Менеджер черги завдань може працювати у власному потоці чи в потоці реактора та реагувати на подію "newJob".

Менеджер черги завдань виконує наступні дії:

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

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

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


3
+1 за те, що дуже ретельно. Кілька посилань для допитливого читача були б приголомшливими.
sam hocevar

1

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

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