Як уникнути "Blob-систем" в компонентній системі сутності?


10

В даний час я стикаюся з такою проблемою:

Я намагаюся написати клон понг, використовуючи систему компонент сутності (ECS). Я написав "рамки" все сам. Отже, існує клас, який управляє сутностями з усіма компонентами. Потім є самі компоненти компонентів. І останнє, є мої системи, які просто отримують всі сутності, які мають компоненти, необхідні цій системі.

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

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

Наприклад: Мої весла можуть стикатися з бордюрами. Якщо це станеться, їх швидкість встановлюється на нуль. Мій м'яч може також стикатися з бордюрами. Але в цьому випадку його швидкість просто відображається на нормальній межі, і це відображається. Для цього я дав м'ячу додатковий компонент фізики, який просто говорить: "Гей, ця річ не припиняється, вона відображає". Тож фактично компонент фізики не має реальних даних. Це порожній клас, який просто існує, щоб повідомити системі, якщо об’єкт відображає або зупиняється.

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

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

Я думаю, що занадто складно? Як мені впоратися з цією проблемою?

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

Але це також не здається правильним рішенням для мене, бо, наприклад:

  1. Моїй системі після зіткнення руху потрібні сутності, які мають компонент позиції, компонент руху та компонент зіткнення. Тоді вона встановила б швидкість сутності на нуль.
  2. Системі фізики після зіткнення потрібні сутності, які мають позиційну складову, компонент руху, компонент зіткнення та компонент фізики. Тоді він би відображав вектор швидкості.

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

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

Відповіді:


11

Так, ти думаєш занадто складно.

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

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

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

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


Дуже дякую. Я хотів побудувати гру за допомогою ECS, щоб просто подивитися, як вона масштабується, і чи справді це приємно використовувати, як я читав у статтях та навчальних посібниках. Моя проблема полягала в тому, що я подумав: "Зараз у мене є ECS, і цим все потрібно керувати". Тому я планував також написати систему частинок у зв'язку з ECS. Крім того, я читав у деяких статтях, що кожен компонент повинен мати лише деякі основні дані та нічого більше. Це часто моя проблема ... Я думаю, що це занадто складно.
M0rgenstern

Я хотів побудувати гру за допомогою ECS, щоб просто подивитися, як вона масштабується, і чи справді це приємно використовувати, як я читав у статтях та навчальних посібниках . Якщо це ваша мета, я рекомендую вам переглянути існуючі системи компонентів / об'єктів, а не будувати власну. Завантажте Unity3D, який, мабуть, "настільки чистий Компонент", і пограйте там. Набагато швидше розуміння, ІМХО.
Імі

3
@lmi: Єдність не є системою компонентів сутності, хоча вона базується на компонентах. ECS має кілька більш суворих рекомендацій ( ніколи не вважайте шаблон як правила), ніж просто мати та використовувати компоненти ігрових об'єктів. Через низку статей ECS зараз популярний у деяких сегментах розробників ігор, тому виникає багато питань щодо ECS, а не дизайну на основі компонентів взагалі.
Шон Міддлічч

12

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

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

По-перше, не робіть своїх компонентів такими маленькими. Немає причин мати дрібнозернисті компоненти, такі як "рух". У вашій грі немає загального руху. У вас є весла, рух яких щільно пов'язаний з входом або AI (і насправді не використовуєте швидкість, прискорення, відновлення тощо), і у вас є м'яч, який має чітко визначений алгоритм руху. Просто майте компонент PaddleController і компонент BouncingBall або щось подібне. Якщо / коли ви отримаєте більш складну гру, то можете потурбуватися про наявність більш загального компонента PhysicsBody (який у "справжніх" двигунах - це, по суті, зв'язок між ігровим об'єктом і тим, що використовує Havok / PhysX / Bullet / внутрішній об'єкт API) Box2D / тощо), що вирішує різноманітні ситуації.

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

Для користувацьких фізичних двигунів пам’ятайте, що вам дозволяється мати дані про компоненти. Може бути, загальна складова фізики понга має дані, що вказують, якими осями вона може рухатися (скажімо, vec2(0,1)як множник для весла, який може рухатися лише по осі Y, а vec2(1,1)для кулі, що вказує, що він може рухатися), прапор або поплавок, що вказує на доброту м'яч, як правило, знаходиться на, 1.0а весла на базі0.0), характеристики прискорення, швидкість тощо. Намагання розділити це на мільярд різних мікрокомпонентів для кожної частини високозалежних даних суперечить тому, що ECS спочатку мав робити. Зберігайте речі, які використовуються разом, в тому самому компоненті, де це можливо, і розбивайте їх лише тоді, коли є велика різниця в тому, як кожен ігровий об’єкт використовує ці дані. Існує аргумент, щоб зробити для Понга фізика між м'ячем і веслами досить різною, щоб бути окремими компонентами, але для більшої гри мало підстав намагатися зробити 20 компонентів, щоб зробити те, що добре працює в 1-3.

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


1
Дійсно, дякую! Я знаю, що ECS не дуже добре розраховує таку маленьку гру, як понг. Але я використав це лише для того, щоб побачити, як така річ насправді реалізується та як вона працює. Я зробив компоненти такими маленькими, бо саме це я читав здебільшого в деяких статтях. Мати багато компонентів і кожен компонент містить лише елементарні дані. Отже, я правильно розумію, що ви пропонуєте використовувати суміш між успадкуванням та ECS? Як ви кажете, «м'яч і весла досить різні, щоб бути окремими компонентами». Так, наприклад, я даю їм як компонент Рух / Позиція (можливо, як один компонент) і
M0rgenstern

1
Що б не працювало. Зосередьтеся на створенні гри. Я буквально просто мав би компонент під назвою, Ballякий містить усю логіку для м'яча, як рух, підстрибування тощо, і Paddleкомпонент, який приймає вклад, але це я. Те, що має для вас найбільше сенсу, виходить з вашої дороги і дозволяє вам зробити гру - це "правильний спосіб" робити речі.
Шон Міддлічч

3
Я буквально просто мав би компонент під назвою Ball, який містить усю логіку для м'яча, як рух, підстрибування тощо, і компонент Paddle, який бере вклад, але це я. І тому для кожного програміста існує одна думка про те, "про що складається компонентна система". Я рекомендую НЕ робити це так, як ця пропозиція, за винятком того, що ви повністю думаєте в класичних системах Entity і змушені використовувати систему компонентів, але не хочете дивитись, що насправді відрізняються.
Імі

2
@lmi: попрацювавши над кількома великими іграми / двигунами з компонентами і побачивши з перших рук, чому ми використовуємо компоненти, ні, надмірно зернисті компоненти - це лише більше клопоту, ніж вони варті. Компоненти - це не чарівна куля; вони є одним із багатьох інструментів в наборі інструментів розробника ігор. Використовуйте їх так, щоб вони допомагали, а не таким чином, щоб вони просто додавали більше розумових та тривалих витрат у систему. Якщо єдине , що має кульковий фізик м'яч, є нульове перевага відокремлюючи його від інших кулькових властивостей. Якщо і коли це зміниться, розділіть їх тоді і тільки тоді.
Шон Міддлічч

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

-2

На мою думку *), ваша найбільша проблема з компонентами полягає в наступному: компоненти тут НЕ, щоб сказати іншим, що робити. Компоненти тут, щоб робити речі. У вас немає компонента, щоб просто зберігати пам'ять про якусь річ, а потім змусити інші компоненти працювати над цим. Ви хочете, щоб компоненти, які виконують дані, отримані ними.

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

  • Ви насправді хочете перевернути залежність: Інший компонент повинен слухати події / повідомлення / передачі / гачки / ховеверіонаметеми, щоб виконати їх логіку у відповідь на ваш поточний компонент. Поточний компонент навіть не повинен знати, що є "інший" компонент. Найчастіше це трапляється, якщо ви виявляєте виклик різних компонентів (навіть у різних блоках інших / корпусів) з функціоналом, який насправді не пов'язаний з вашим поточним методом. Подумайте про все це Invalidate()або SetDirty()заклики до інших компонентів.
  • У вас може бути занадто багато компонентів. Якщо два компоненти просто не можуть жити один без одного і постійно потребують пошуку даних та виклику методів один до одного, то просто об'єднайте їх. Очевидно, функціонал, який вони надають, настільки заплутаний, що насправді це лише одне.

До речі, це стосується всіх видів систем, не тільки систем Entity / Component, а й класичного успадкування з простими функціями "GameObject" або навіть бібліотеками.

*) Дійсно тільки моя . Думки сильно різняться щодо Whats Da Real Component Systemz (TM)

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