Багато джерел руху в системі сутності


9

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

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

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

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

У традиційному OO-рішенні я мав би якийсь MoveByклас, який містить відстань / час та масив тих, що знаходяться в моєму ігровому об’єктному класі. Кожен кадр я повторюю через усі MoveBy, і застосовую його до позиції. Якщо a MoveByдосяг свого часу закінчення, вийміть його з масиву.

Що стосується системи сутності, я трохи плутаюсь, як я повинен повторювати таку поведінку.

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

PositionComponent що містять x, y

MoveByComponent що містять x, y, time

Entityякий має і a, PositionComponentі aMoveByComponent

MoveBySystemщо зовнішній вигляд для об'єкта з обома цими компонентами, і додає значення MoveByComponentдо PositionComponent. Коли значення timeдосягається, він видаляє компонент із цього об'єкта.

Я трохи розгублений у тому, як би я робив те саме, що й багато рухів.

Мої початкові думки полягають у тому, що я мав би:

PositionComponent, MoveByComponentте саме, що вище

MoveByCollectionComponentякий містить масив MoveByComponents

MoveByCollectionSystemщо шукає сутність з a PositionComponentі a MoveByCollectionComponent, ітерація через MoveByComponents всередині неї, застосовуючи / видаляючи за необхідності.

Я думаю, що це більш загальна проблема: мати багато однакових компонентів і бажати, щоб відповідна система діяла на кожну. Мої сутності містять свої компоненти всередині хеша типу компонента -> компонент, тому суворо мають лише 1 компонент певного типу на сутність.

  1. Це правильний спосіб дивитися на це?

  2. Чи має суб'єкт господарювання завжди мати лише один компонент даного типу?


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

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

Я роблю це так: у мене є PlayerInputComponent та AIInputComponent (або системи), які скажуть MobileBehaviorComponent, що при натисканні клавіатури або на AI, думаючи, що мобільний має кудись переміститися, MobileBehaviorComponent збереже, що він повинен кудись рухатися (у ньому є FSM всередині мобільних дій) і якась система перемістить його. Ваша деталізація просто занадто велика, з компонентами вищого рівня, такими як Transform, Model, Light, Mob, все працює так само добре. Також мені ніколи не потрібно було видаляти компоненти - я думаю, що вони більше схожі на те, що описує ігровий об’єкт, тому він не може просто зникнути.
Кікаймару

Цей конкретний приклад MoveBy був лише прикладом. Питання було більше про те, як ви поєднуєте речі разом. Якщо мені потрібно конкретно сказати: «рухатись на x = 5 і y = 6 за 5 секунд», «рухатись на x = 10 y = 2 за 10 секунд», водночас це я б це робив?
Липкий

Що ви маєте на увазі під "складеними разом"? Як додавання швидкостей? Отже, якби ви склалися move x by 10 in 2 secondsі move x by -10 in 2 secondsсутність стояла б ідеально нерухомо?
Том Даллінг

Відповіді:


6

Для вашого сценарію ми зазвичай додаємо три компоненти до ігрового об’єкта:

  1. TransformComponent (положення, орієнтація, масштаб)
  2. Компонент швидкості (швидкість, напрямок)
  3. ControllerComponent

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

BehaviorTree* tree(new SequentialNode());
tree->addChild(new MoveToNode(x,y,z));
tree->addChild(new WaitNode(30));
tree->addChild(new MoveToNode(a,b,c));
tree->addChild(new WaitNode(30));
gameObject->addComponent(new AIController(tree));

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

Вищевказаний код просто переміщує ігровий об’єкт з нерестового місця на x, y, z у світовому просторі, потім чекає мінімум 30 секунд, потім переміщує ігровий об’єкт на місце a, b, c, а потім чекає ще 30 секунд. Як тільки очікування закінчено, послідовність поведінки закінчена, тому вона повторюється з самого початку.

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


1

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

Наприклад: створіть базовий клас контролера методом run (), або якщо вам не сподобається ім'я, викликайте його think (), update () або позначте галочку (). Потім ви успадковуєте з нього і створюєте MoveController, NPCController, PlayerInputController (для об'єкта гравця), PhysicController; тоді ви реалізуєте метод run (). Я поставив би ваш MoveByComponent в MoveController, а не в Entity.

Ці Контролери можуть бути ініційовані кожним суб'єктом господарювання, якщо вони мають дані, характерні для суб'єкта господарювання. Їх можна знищити або скинути для повторного використання. Крім того, ви можете використовувати контролер для переміщення групи сутностей, наприклад, у грі RTE, якщо вам потрібно переміщувати різні підрозділи як групу, якщо контролер по кожному блоку може зашкодити ігровій діяльності, тоді ви можете просто призначити всі одиниці до GroupController або LegionController і нехай він переміщує одиниці як частину організованої групи. У боротьбі, якщо гра дозволяє індивідуальну поведінку одиниці, і, мабуть, це робить більшість ігор, вам доведеться перейти на UnitController, але краще це робити лише за потреби, ніж з початку.

У моїй грі, що розвивається, у мене є MoveController, який переміщує сутностей по шляху, один MoveController існує для кожного NPC та персонажа гравця. Іноді створюється одна для коробок або скелі, яку гравець може штовхати. PhysicController, лише один екземпляр, який перевірятиме позиції всіх призначених йому об'єктів, якщо якась сутність стикається з іншою призначеною сутністю, отримана позиція обох обчислюється (вона насправді робить більше, але ви отримуєте ідею). NPCController - це AI, один екземпляр на NPC. Він перевіряє ситуацію NPC і вирішує, куди рухатися, а потім підштовхує шлях до MoveController, який фактично переміщує NPC. Контролери мають пріоритет, тому я можу заздалегідь визначити їх порядок, PhysicController - останній, який виконується.

Я виступаю за контролери, але це не єдиний "правильний" варіант. Наприклад, я пам’ятаю інтерфейс Entity в двигуні Cafu, який має метод think () у самій Entity, користувач класу повинен успадкувати від Entity та реалізувати think (), я пам’ятаю похідний клас під назвою CompanyBot (що поставляється із прикладом гра), які роблять певну перевірку зіткнень у цьому методі, як це називається "думаю", ми можемо припустити, що AI код теж очікується. У той час як двигун NeoAxis (востаннє я його заглядав) AI і фізика відокремлені від сутності.

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


Це в основному дизайн OO, який ми вже маємо зараз. Суб'єкт, з похідними (Характер, Монстр) тощо, я очолював команду з нас, яка працює над цією грою повний робочий день майже 2 роки, і коли всі змінюють за бажанням, це стає жахливим, жахливим кодова база - і починає тривати тривожно довго, щоб отримати нові функції. Ідея Entity System, здається, саме те , що я шукаю, тому, хоча ваша відповідь не зовсім актуальна, вам слід прочитати самі посилання у верхній частині питання, щоб дізнатися, чи можуть вони допомогти вам :)
Липкий

@ Стичний Я мушу визнати, що Node System плюс Entity, що складається з компонентів, є розумним способом представити різні необхідні системи, ніж запропонований нами підхід контролерів, який є менш розвиненою версією. Вам справді не потрібна моя відповідь.
Хатору Хансу,

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