Зв'язок, керований подіями в ігровому двигуні: Так чи ні?


62

Я читаю ігрове кодування завершено, і автор рекомендує комунікацію, керовану подією, між ігровими об'єктами та модулями.

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

Це перевірений і рекомендований підхід? Як я повинен вирішити, чи використовувати його?


Привіт Джеймс, дякую за вашу відповідь. Мені це подобається, хоча книга описує події, керовані подіями, як дійсно складну систему, яка, здавалося б, забирає значно багато ресурсів процесора.
Bunkai.Satori

Введіть його у відповідь та додайте у посилання на огляд високого рівня системи обміну подіями, яку я дав як відповідь на переповнення стека. Насолоджуйтесь! Пам'ятайте лише, що те, що деякі вважають складним, не повинно бути :)
Джеймс,

Ви можете перевірити цю відповідь , як добре зроблено з допомогою C ++ 11: stackoverflow.com/a/22703242/2929762
user2826084

libuvостаннім часом стала успішною бібліотекою подій. (Це в C. Node.js - це найвідоміший приклад використання.)
Анко,

Відповіді:


46

Це розширення мого коментаря до повної відповіді, як було запропоновано.

Так , просто і просто. Спілкування має відбуватися, і поки існують ситуації, коли "ми ще там?" -типичне опитування потрібно, щоб перевірити, чи слід робити щось інше, як правило, витрачає час. Натомість ви можете змусити їх реагувати на речі, про які їм кажуть. Крім того, чітко визначений шлях зв'язку між об'єктами / системами / модулями значно покращує паралельні налаштування.

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

РЕДАКТУВАННЯ : Щоб вирішити питання щодо коментарів щодо того, яким чином ви знаєте, які об’єкти повинні отримати повідомлення : Самі об’єкти повинні Requestбути повідомлені про події. Вашому EventMessagingSystem(EMS) знадобиться Register(int iEventId, IEventMessagingSystem * pOjbect, (EMSCallback)fpMethodToUseForACallback)як і відповідність Unregister(зробити унікальний запис для iEventIdвказівника об'єкта та зворотного виклику). Таким чином, коли об’єкт хоче дізнатися про повідомлення, яке він може отримати Register()із системою. Коли йому більше не потрібно знати про події, він можеUnregister(). Зрозуміло, що ви хочете отримати пул цих об'єктів реєстрації зворотних викликів та ефективний спосіб додавання / видалення їх зі списків. (Я зазвичай використовую масиви для самостійного замовлення; вигадливий спосіб сказати, що вони відслідковують власні розподіли між стеком пулу невикористаних об'єктів та масивами, які змінюють їх розміри на місце за потреби).

EDIT : Для повністю працюючої гри з циклом оновлення та системою обміну подіями, ви можете перевірити проект моєї старої школи . Посилання, пов’язане з переповненням стека, також посилається на нього.


Привіт Джеймс, оскільки я більше замислююся над системою внутрішніх повідомлень про події, я думаю, що це не потребує додаткових витрат на двигун. Наприклад, якщо на екрані є 50 об'єктів, але лише 5 з них повинні змінити свою поведінку; за традиційною системою, всі 50 об’єктів повинні перевірити чи всі їх можливі дії, щоб побачити, чи потрібно щось робити. Однак із використанням повідомлень про події лише 5 повідомлень будуть надіслані цим 5 об’єктам із конкретною зміною дії. Це виглядає як підхід для економії часу.
Bunkai.Satori

Те, як працює система, пов'язана з моєю вищезгаданою відповіддю, полягає в тому, що об’єкти реєструються лише для того, щоб чути про потрібні повідомлення. Ми використовували б це для наших переваг у відеоіграх, де на рівні може бути 100-200 об'єктів, але ви тільки "активувати" ті, з ким гравець може безпосередньо взаємодіяти, зберігаючи кількість прослуховуваних речей приблизно 10 або близько того. Загалом цей тип системи повинен бути "розумнішим", ніж "ми там ще є?" система опитування, і повинна зменшити накладні витрати двигуна, як мінімум, що стосується зв'язку.
Джеймс

Є одна річ, пов’язана із системою, керованою подіями, що мене бентежить: У традиційній системі, де кожен об'єкт має попередньо визначений набір методів (OnUpdate (), OnMove (), OnAI (), OnCollisionCheck () ...), регулярно викликається, кожен об'єкт є відповідальна за перевірку та управління своїм станом. У системі, керованій подіями, має бути певна умова контролю системи кожного об'єкта, а потім надсилання повідомлень тим, де була виявлена ​​якась подія. Для мене це стандартизує можливі стани об'єкта і обмежує свободу створення унікальної поведінки об'єкта. Це правда?
Bunkai.Satori

Шаблон спостерігача - типова альтернатива опитування. en.wikipedia.org/wiki/Observer_pattern
Ricket

1
@ hamlin11 Радий, що ця інформація все ще допомагає людям :) Що стосується реєстрації, якщо це трапиться зовсім небагато, пам’ятайте, що ви хочете оптимізувати її за швидкістю, мати пул об’єктів реєстрації, з яких можна звернутись тощо
James

22

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

І це добре, адже коли ти закінчиш, ти насправді матимеш гру, а гра набагато крутіша, ніж система передачі повідомлень.


2
Привіт Джо, дякую за вашу відповідь, мені це подобається. Ви вважаєте, що не потрібно штучно підштовхувати будь-який підхід. Я повинен розробляти додатки так, як, на мою думку, спрацюють, і якщо щось пізніше не вийде, я просто повторю його.
Bunkai.Satori

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

16

Краще питання, які альтернативи є? У такій складній системі з правильно розділеними модулями для фізики, AI тощо, як ще можна оркеструвати ці системи?

Передача повідомлень здається "найкращим" рішенням цієї проблеми. Я зараз не можу придумати альтернативи. Але є чимало прикладів передачі повідомлень на практиці. Фактично, операційні системи використовують передачу повідомлень для декількох своїх функцій. З Вікіпедії :

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

(Міжпроцесовий зв'язок - це зв'язок між процесами (тобто запущеними екземплярами програм) в середовищі операційної системи)

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

Я також задав питання щодо переповнення стека, "Структури даних для передачі повідомлень у межах програми?" , яку ви, можливо, захочете прочитати.


Привіт Ricket, дякую за вашу відповідь. Ви запитали, які ще способи можна використовувати, щоб ігрові об’єкти спілкувалися один з одним. Що мені спадає на думку, це прямі методи дзвінків. Ясно, що це не дає вам стільки гнучкості, але, з іншого боку, це дозволяє уникнути генерації повідомлень про події, передачі, читання тощо. Ми все ще говоримо про мобільні платформи, а не про ігри високого класу. Операційна система широко використовує внутрішню систему обміну повідомленнями. Однак він не розроблений для роботи в режимі реального часу, де навіть невеликі затримки викликають зриви.
Bunkai.Satori

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

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

Так, тепер ми почали обговорювати закономірності. Я чула трохи про цей підхід до програмування. Тепер я починаю розуміти, що таке закономірності. Зовсім інший погляд на дизайн додатку. Ви масово керуєте об'єктами, використовуючи той самий код для перевірки кожного об'єкта. Після перевірки об'єкта ви відповідно встановите його атрибути.
Bunkai.Satori

1
На питання "Структури даних ..." є дивовижна відповідь. Я б сказав, що обрана відповідь та супровідна стаття Nebula3 - найкращий опис архітектури ігрового двигуна їх розміру, який я коли-небудь бачив.
deft_code

15

Повідомлення зазвичай працюють добре, коли:

  1. Річ, що надсилає повідомлення, не хвилює, чи отримана вона.
  2. Відправника не потрібно отримувати негайну відповідь від одержувача.
  3. Можливо, декілька приймачів прослуховують одного відправника.
  4. Повідомлення надсилатимуться нечасто або непередбачувано. (Іншими словами, якщо кожному об'єкту потрібно отримувати повідомлення "оновлення" кожен кадр, повідомлення насправді не купують вас багато.)

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


4

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

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

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

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


+1 за гарну додаткову інформацію. Привіт, MrCranky, спасибі Згідно з вашими словами, варто було б розглянути систему обміну подіями навіть для мобільних ігор. Однак планування не слід нехтувати, і слід дуже добре враховувати, де система обміну повідомленнями буде використовуватися.
Bunkai.Satori

4

Ну, я знаю, що ця посада досить стара, але я не втримався.

Нещодавно я побудував ігровий двигун. Він використовує бібліотеки 3d-партій для візуалізації та фізики, але я написав основну частину, яка визначає та обробляє сутності та логіку гри.

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

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

Незважаючи на примітивну систему повідомлень, я б сказав, що система значною мірою є "циклом оновлення на основі".

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

Але я також думаю, що у чистої системи на основі циклу оновлення, як у мене, є і деякі проблеми.

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

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


Ви побачите, що сутності стають базами кодів монстрів, яким стає важко керувати з будь-якою складністю в грі. Ви з’єднаєте їх разом, і ви зможете додати або змінити функції. Розбивши свої функції на невеликі компоненти, вам буде легше підтримувати та додавати функції. Тоді виникає питання, як спілкуються ці компоненти? Відповідь - це події з одного компонента, що піднімає функції іншого, передаючи примітивні дані в аргументах.
user441521

3

Так. Це дуже ефективний спосіб спілкування ігрових систем один з одним. Події допомагають вам роз’єднати багато систем і дають можливість навіть складати речі окремо, не знаючи про існування один одного. Це означає, що ваші заняття можна простіше скласти за прототипом, а часи компіляції - швидші. Що ще важливіше, ви закінчуєте плоский дизайн коду замість безладу залежності.

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

Ще одна перевага: Ви можете прослуховувати кілька підсистем для однієї події. Наприклад, всі ваші віддалені види (гравці) можуть автоматично підписатися на подію створення сутності та породжувати сутності у кожного клієнта з невеликою роботою з вашого боку. Уявіть, як би більше працювало, якби ви не використовували події: вам доведеться Update()десь телефонувати або, можливо, дзвонити view->CreateEntityз логіки гри (де знання про вигляд та необхідну інформацію не належить). Важко вирішити цю проблему без подій.

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

Детальніше та реалізація тут .


Чудові бали, хоча й однобічні. Я завжди з підозрою спільності: Чи є анти -використовувати футляри для подій?
Анко

1
Точки проти використання: коли ви абсолютно повинні мати пряму відповідь. Коли все, що ви хочете зробити на якійсь події, завжди виконується безпосередньо і в одній темі. Якщо зовнішньої затримки абсолютно немає, це може затримати завершення дзвінків. Коли у вас є лише лінійні залежності. Коли ти рідко робиш кілька речей одночасно. Якщо ви подивитесь на node.js, всі виклики io залежать від подій. Node.js - це одне місце, де події були реалізовані на 100% правильно.
користувач2826084

Систему подій не потрібно асинхронізувати. Ви можете використовувати підпрограми для імітації асинхронізації, отримуючи синхронізацію, коли це потрібно.
user441521

2

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

  • Ігрові двигуни обробляють велику кількість даних.
  • Ігри повинні бути швидкими (20-30 FPS має бути мінімальним).
  • Часто доводиться знати, чи щось було зроблено чи коли це буде зроблено.

При загальному підході розробника ігор, "він повинен бути максимально ефективним", така система обміну повідомленнями не є такою поширеною.

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


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

Я теж не згоден з цим. Кількість механізмів ігрових даних, з якими обробляються, в основному не має значення, оскільки обмін повідомленнями подій призначений для зв'язку підсистеми та підсистеми. Ігрові об’єкти не повинні спілкуватися безпосередньо з іншими ігровими об’єктами (хоча користувацькі обробники подій в об'єктах можуть бути винятком). Завдяки цій порівняно невеликій кількості підсистем та їх областям, що представляють інтерес, вартість продуктивності добре розробленої магістралі обміну повідомленнями в багатопотоковому двигуні незначна.
Ян Янг
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.