Ayer, leí una presentación de GDC Canadá sobre el sistema de entidades de Atributo / Comportamiento y creo que es bastante bueno. Sin embargo, no estoy seguro de cómo usarlo de manera práctica, no solo en teoría. En primer lugar, te explicaré rápidamente cómo funciona este sistema.
Cada entidad del juego (objeto del juego) se compone de atributos (= datos, a los que se puede acceder mediante comportamientos, pero también mediante 'código externo') y comportamientos (= lógica, que contienen OnUpdate()
y OnMessage()
). Entonces, por ejemplo, en un clon de Breakout, cada ladrillo estaría compuesto de (¡ejemplo!): PositionAttribute , ColorAttribute , HealthAttribute , RenderableBehaviour , HitBehaviour . El último podría verse así (es solo un ejemplo no funcional escrito en 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);
}
}
}
Si está interesado en este sistema, puede leer más aquí (.ppt).
Mi pregunta está relacionada con este sistema, pero generalmente cada sistema de entidad basado en componentes. Nunca he visto cómo ninguno de estos realmente funciona en juegos de computadora reales, porque no puedo encontrar ningún buen ejemplo y si encuentro uno, no está documentado, no hay comentarios y, por lo tanto, no lo entiendo.
Entonces, ¿qué quiero preguntar? Cómo diseñar los comportamientos (componentes). He leído aquí, en GameDev SE, que el error más común es hacer muchos componentes y simplemente "hacer que todo sea un componente". He leído que se sugiere no hacer la representación en un componente, sino hacerlo fuera de él (por lo tanto, en lugar de RenderableBehaviour , tal vez debería ser RenderableAttribute , y si una entidad tiene RenderableAttribute establecido en verdadero, entonces Renderer
(clase no relacionada con componentes, pero para el propio motor) ¿debería dibujarlo en la pantalla?).
Pero, ¿qué hay de los comportamientos / componentes? Digamos que tengo un nivel, y en el nivel, hay un Entity button
, Entity doors
y Entity player
. Cuando el jugador choca con el botón (es un botón de piso, que se alterna por presión), se presiona. Cuando se presiona el botón, se abren las puertas. Bueno, ahora como hacerlo?
Se me ocurrió algo como esto: el jugador tiene CollisionBehaviour , que comprueba si el jugador choca con algo. Si choca con un botón, envía un CollisionMessage
a la button
entidad. El mensaje contendrá toda la información necesaria: quién colisionó con el botón. El botón tiene ToggleableBehaviour , que recibirá CollisionMessage
. Verificará con quién chocó y si el peso de esa entidad es lo suficientemente grande como para alternar el botón, el botón se alterna. Ahora, establece el atributo ToggledAttribute en verdadero. De acuerdo, pero ¿y ahora qué?
¿Debería el botón enviar otro mensaje a todos los demás objetos para decirles que se ha activado? Creo que si hiciera todo de esta manera, tendría miles de mensajes y sería bastante complicado. Entonces, quizás esto sea mejor: las puertas comprueban constantemente si el botón que está vinculado a ellas está presionado o no, y cambia su atributo abierto en consecuencia. Pero entonces significa que el OnUpdate()
método de las puertas hará algo constantemente (¿es realmente un problema?).
Y el segundo problema: ¿qué pasa si tengo más tipos de botones? Uno es presionado por la presión, el segundo se alterna disparándole, el tercero se alterna si se vierte agua sobre él, etc. Esto significa que tendré que tener comportamientos diferentes, algo como esto:
Behaviour -> ToggleableBehaviour -> ToggleOnPressureBehaviour
-> ToggleOnShotBehaviour
-> ToggleOnWaterBehaviour
¿Es así como funcionan los juegos reales o simplemente soy estúpido? Tal vez podría tener solo un ToggleableBehaviour y se comportará de acuerdo con ButtonTypeAttribute . Entonces, si es un ButtonType.Pressure
, hace esto, si es un ButtonType.Shot
, hace otra cosa ...
Entonces que quiero? Me gustaría preguntarle si lo estoy haciendo bien, o simplemente soy estúpido y no entiendo el punto de los componentes. No encontré ningún buen ejemplo de cómo funcionan realmente los componentes en los juegos, encontré solo algunos tutoriales que describen cómo hacer el sistema de componentes, pero no cómo usarlo.
fuente
Entity
tiene unEntityBody
, que abstrae todos los bits feos. Los comportamientos pueden leer la posición desde elEntityBody
, aplicarle fuerzas, usar las articulaciones y los motores que tiene el cuerpo, etc. Tener una simulación física de tan alta fidelidad como Box2D ciertamente trae nuevos desafíos, pero son bastante divertidos.Component
/System
mencionado varias veces en los tableros. Nuestras implementaciones de hecho tienen bastantes similitudes.