Вчора я прочитав презентацію від GDC Canada про систему об'єктів Attribute / Behavior, і думаю, що це досить чудово. Однак я не впевнений, як це використовувати практично, а не лише теоретично. Перш за все, я швидко поясню вам, як працює ця система.
Кожна ігрова сутність (ігровий об’єкт) складається з атрибутів (= даних, до яких можна отримати поведінку, але також і «зовнішнього коду») та поведінки (= логіка, яка містить OnUpdate()
і OnMessage()
). Так, наприклад, у клоні прориву кожна цегла складається з (приклад!): PositionAttribute , ColorAttribute , HealthAttribute , RenderableBehaviour , HitBehaviour . Останній може виглядати так (це просто неробочий приклад, написаний на C #):
void OnMessage(Message m)
{
if (m is CollisionMessage) // CollisionMessage is inherited from Message
{
Entity otherEntity = m.CollidedWith; // Entity CollisionMessage.CollidedWith
if (otherEntity.Type = EntityType.Ball) // Collided with ball
{
int brickHealth = GetAttribute<int>(Attribute.Health); // owner's attribute
brickHealth -= otherEntity.GetAttribute<int>(Attribute.DamageImpact);
SetAttribute<int>(Attribute.Health, brickHealth); // owner's attribute
// If health is <= 0, "destroy" the brick
if (brickHealth <= 0)
SetAttribute<bool>(Attribute.Alive, false);
}
}
else if (m is AttributeChangedMessage) // Some attribute has been changed 'externally'
{
if (m.Attribute == Attribute.Health)
{
// If health is <= 0, "destroy" the brick
if (brickHealth <= 0)
SetAttribute<bool>(Attribute.Alive, false);
}
}
}
Якщо вас зацікавила ця система, ви можете прочитати більше тут (.ppt).
Моє запитання пов'язане з цією системою, але, як правило, з кожною складовою системою сутності. Я ніколи не бачив, як будь-який з цих дійсно працює в реальних комп'ютерних іграх, тому що я не можу знайти жодних хороших прикладів, і якщо я знайду його, це не задокументовано, немає коментарів, і тому я не розумію цього.
Отже, що я хочу запитати? Як проектувати поведінку (компоненти). Я читав тут, на GameDev SE, що найпоширеніша помилка - це зробити багато компонентів і просто "зробити все складовою". Я читав, що пропонується не робити візуалізацію в компоненті, а робити це поза нею (тому замість RenderableBehaviour , можливо, це має бути RenderableAttribute , а якщо суб'єкт господарювання має RenderableAttribute встановлений на true, то Renderer
(клас не пов'язаний з компоненти, але до самого двигуна) слід намалювати його на екрані?).
Але як щодо поведінки / компонентів? Скажімо, що у мене рівень, і в рівні є Entity button
, Entity doors
і Entity player
. Коли гравець стикається з кнопкою (це кнопка підлоги, яка перемикається тиском), її натискають. Коли кнопка натискається, вона відкриває двері. Ну, а тепер як це зробити?
Я придумав щось подібне: у гравця є CollisionBehaviour , який перевіряє, чи гравець стикається з чимось. Якщо він стикається з кнопкою, він посилає CollisionMessage
до button
лиця. Повідомлення міститиме всю необхідну інформацію: хто зіткнувся з кнопкою. Кнопка отримала ToggleableBehaviour , який отримає CollisionMessage
. Він перевірить, з ким це зіткнулося, і якщо вага цієї сутності досить велика, щоб перемикати кнопку, кнопка перемикається. Тепер він встановлює значення ToggledAttribute для значення true. Добре, але що тепер?
Чи повинна кнопка надіслати ще одне повідомлення всім іншим об’єктам, щоб сказати їм, що воно перемкнулося? Я думаю, що якби я зробив все так, я мав би тисячі повідомлень, і це стане досить безладним. Тому, можливо, це краще: двері постійно перевіряють, натиснута чи ні кнопка, пов’язана з ними, і відповідно змінює її OpenedAttribute . Але це означає, що OnUpdate()
метод дверей буде постійно щось робити (чи це справді проблема?).
І друга проблема: що робити, якщо у мене більше видів кнопок. Одного натискають на тиск, другого перемикають, стріляючи по ньому, третього вмикають, якщо на нього наливають воду тощо. Це означає, що мені доведеться мати різні поведінки, приблизно так:
Behaviour -> ToggleableBehaviour -> ToggleOnPressureBehaviour
-> ToggleOnShotBehaviour
-> ToggleOnWaterBehaviour
Це як справжні ігри, чи я просто дурний? Можливо, я міг би мати лише один ToggleableBehaviour, і він буде вести себе відповідно до ButtonTypeAttribute . Отже, якщо це a ButtonType.Pressure
, він робить це, якщо це a ButtonType.Shot
, він робить щось інше ...
То що я хочу? Я хотів би запитати вас, чи правильно я це роблю, чи я просто дурний, і я не розумів суті компонентів. Я не знайшов хорошого прикладу того, як компоненти дійсно працюють в іграх, я знайшов лише кілька підручників, що описують, як зробити систему компонентів, але не як її використовувати.