Створення Сутності як сукупність


10

Нещодавно я запитав про те, як відокремити суб'єкти від їх поведінки та головну відповідь, пов’язану з цією статтею: http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/

Кінцева концепція, про яку тут написано, - це: ОБ'ЄКТ ЯК ЧИТА АГРЕГАЦІЯ.

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

Моє сучасне мислення все ще передбачає наявність конкретного класу для кожного типу сутності, який потім реалізує відповідні інтерфейси (IMoveable, ICollectable, ISpeakable тощо).

Як я можу створити сутність як сукупність, не маючи конкретного типу для цієї сутності?


Якщо ви все ще зацікавлені, я можу надіслати вам свою маленьку систему сутності на C #. Це не дивно , але це працює.
Качка комуністична

Відповіді:


6

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

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

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

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

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


3

Як Unity робить це, що всі сценарії (у вашому випадку, ігровий код, специфічний для типу ігрового об'єкта) походять від базового класу MonoBehaviour, який сам походить від більш відповідного для вашого Componentкласу класу. Ви ніколи не редагуєте (і не маєте доступу до коду) класу GameObject.

Ігровий об’єкт відповідає за вміщення всіх цих Components. Він також нібито відповідає за виклик відповідних функцій на них (тобто Update). Unity використовує роздуми, щоб визначити, які функції потрібно викликати (дивіться розділ "Замінні функції" на цій сторінці ), але ви, мабуть, хочете зробити їх віртуальними.

Отже, одним із механізмів, який ви використовуєте в Unity, є отримання компонентів на поточний ігровий об’єкт (або його діти) за типом. Є деякі допоміжні властивості, які обгортають деякі звичні речі. Наприклад, якщо ви хочете отримати доступ до Transformкомпонента ігрового об’єкта (щоб керувати положенням / обертанням / масштабом ігрового об’єкта), вам, як правило, потрібно зробити щось на кшталт this.GetComponent<Transform>().position, але вони перетворюють це на this.transform.positionвиклик помічника . Ще одна поширена модель - це доступ до Rendererкомпонента поточного ігрового об'єкта . Отже, якщо ви хочете зробити щось на зразок змінити матеріал поточного ігрового об’єкта, з іншого сценарію ви можете зробити щось на кшталт this.renderer.material = someOtherMaterial, і ваш ігровий об’єкт належним чином оновиться.

Одним із способів роботи в Unity є те, що їх редактор налаштований таким чином, що ви можете створювати ігрові об’єкти на вашій сцені, які мають вже підключені компоненти. У випадку Unity, всі ігрові об'єкти мають Transformкомпонент, але він також може містити вбудовані типи, як AudioListenerабо Renderer, які роблять те, що ви очікували. Або ви можете додати свої власні компоненти, які роблять все, що ви хочете, щоб вони робили. Редактор також відкриває публічні / серіалізаційні поля на ваших компонентах, тому вам не потрібно робити різні сценарії, якщо ви хочете використовувати один і той же базовий код, але змінити кілька магічних чисел навколо.

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


0

Мені подобається підхід, ближчий до бачення Адама з блогу t-machine. Компоненти повинні бути лише даними, а системи роблять з ними всю роботу.

Дивіться приклад реалізації ES в C #: https://github.com/thelinuxlich/artemis_CSharp

І приклад гри з її використанням (XNA 4): https://github.com/thelinuxlich/starwarrior_CSharp

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