¿Cuál es un nivel apropiado de granularidad para la arquitectura basada en componentes?

26

Estoy trabajando en un juego con una arquitectura basada en componentes. Un Entityposee un conjunto de Componentinstancias, cada una de las cuales tiene un conjunto de Slotinstancias para almacenar, enviar y recibir valores. Funciones de fábrica tales como Playerproducir entidades con los componentes necesarios y las conexiones de ranura.

Estoy tratando de determinar el mejor nivel de granularidad para los componentes. Por ejemplo, en este momento Position, Velocityy Accelerationtodos son componentes separados, conectados en serie. Velocityy Accelerationpodría reescribirse fácilmente en un Deltacomponente uniforme , o Position, Velocityy Accelerationpodría combinarse junto con componentes como Frictiony Gravityen un Physicscomponente monolítico .

¿Debe un componente tener la menor responsabilidad posible (a costa de mucha interconectividad) o los componentes relacionados deben combinarse en monolíticos (a costa de la flexibilidad)? Me estoy inclinando hacia la primera, pero podría usar una segunda opinión.

Jon Purdy
fuente
¿Vas a usar tu propio motor de física o integrar uno existente?
Den
@ Den: estoy escribiendo un código de física , pero no es un motor de ninguna manera. Solo cinemática 2D mundana.
Jon Purdy

Respuestas:

14

Hay una línea entre la granularidad completa, que no genera desperdicio de código o un estado similar a un blob (razón por la cual se favorecen las arquitecturas de componentes) y la usabilidad.

Obviamente, las cosas pueden tener un Position, pero no son necesariamente dinámicas (entonces, ¿por qué tener Velocityy Acceleration?). Sin embargo, algo con un Velocityva a ser un objeto en movimiento, por lo que tiene sentido también haber Accelerationagrupado.

¿Vas a tener un caso donde v y una va a ser necesaria, pero no desea una simulación física para ellos? Del mismo modo, ¿habrá algún punto Gravitysi no son objetos de física?

tl; dr Agrupe lo que tiene sentido.

El pato comunista
fuente
1
Suena justo. Mi sistema tiene muy poca centralización: si un Entitytiene Positionalgunos componentes que hacen que Positionparticipen en la física, entonces Entityes de facto físico. Creo que lo que puedo hacer es agregar algunos componentes para la agrupación lógica y mantener todos los componentes fundamentales en una sola responsabilidad. Por lo que añadir, por ejemplo, una Movablea una Entitytendría el mismo efecto que la adición de una Position, Velocityy Acceleration.
Jon Purdy
6

Para evitar la microgestión de todas y cada una de las variables que sugeriría al comenzar con fuerza, elija divisiones en torno a la responsabilidad y refactorice cuando la situación se presente de forma lógica. Puede comenzar los primeros diseños en papel. En algún momento, estas divisiones groseras de responsabilidad se convertirán en los componentes básicos de sus entidades.

Entonces, para un ejemplo apresurado, tienes Game. El juego se divide en Medio Ambiente + Estado. El entorno se divide en StaticWorld + MovingStuff. El estado se divide en AIControlled + PlayerControlled. La idea general de Daño se divide en TakesDamage + GivesDamage.

Y así.

Muy parecido al consejo común de "¡Crea juegos, no motores!" para los nuevos practicantes recomiendo "¡Crear juegos, no sistemas de componentes elaborados!" porque solo con experiencia personal con un juego en ejecución sabrás si se requiere un complejo sistema de componentes en futuros trabajos.

Patrick Hughes
fuente
No soy un desarrollador nuevo. Si tengo componentes basados ​​en conceptos en lugar de comportamiento (es decir, de arriba hacia abajo o de abajo hacia arriba), ¿mi arquitectura no será más frágil y más elaborada? Puedo implementar cualquier comportamiento que desee a partir de componentes pequeños, pero no siempre puedo obtener el comportamiento deseado de los componentes combinados previamente. Sin mencionar que no puedo predecir todo lo que quiero lograr, incluso en el contexto de un juego.
Jon Purdy
El inconveniente de abajo hacia arriba es que las comunicaciones entre componentes se convierten en un problema, y ​​las personas tienden a comenzar demasiado micro en la escala de lo que están modelando. Principalmente estaba tratando de alejarme del nivel súper micro "xyz es un componente" "la rotación es un componente" "rgb es un nivel de componente" para alguien sin experiencia.
Patrick Hughes
Lo suficientemente justo. Solo quería asegurarme de que te entendía correctamente. Con el sistema de ranura que tengo, es simple y eficiente para que los componentes se comuniquen, por lo que realmente no veo ningún inconveniente en la escala "supermicro". No tengo la intención de refactorizar esto en un motor independiente, pero si lo hago, siempre puedo introducir abstracciones como los grupos de componentes que menciono en mi comentario sobre la respuesta de The Communist Duck.
Jon Purdy
4

Mi conjetura sería combinar componentes que tendrán mucha interacción. En su caso, mantendría la posición en un solo componente y mantendría la velocidad y la aceleración juntas en un componente de física.

Pero depende mucho de las características de su juego (a menos que esté creando un marco sin un juego específico en mente).

XGouchet
fuente
2
El problema de combinar componentes con mucha interacción es que a veces la otra parte no es necesaria.
El pato comunista
4

Me doy cuenta de que esta es una vieja pregunta, pero tal vez alguien encuentre útil esta respuesta.

Creo que eso Systemslo ayudará mejor a comprender cómo construir Componentes. Los sistemas existen en arquitecturas donde los componentes no contienen su propia lógica, aparte de simples getter / setters y funciones auxiliares. Los sistemas operan en entidades que satisfacen los requisitos de los componentes. Esta es la razón por la cual es mejor separar los datos de los componentes tanto como tenga sentido que esos datos se procesen sin los otros datos.

Por ejemplo, puede tener una MovementSystemque actualice sus Entidades en Positionfunción de sus Velocity. Esto podría ser para entidades simples en el juego. Pero, para el Jugador y los Enemigos, es posible que desee un movimiento que Accelerationse procese AcceleratedMovementSystem. Pero para Obstáculos puede que quieras Friction. El terreno también puede tener fricción, pero no tendrá un componente de velocidad. ¿Pero que pasa Gravity? Simplemente agréguelo Player, Enemy y Obstacle, y cree un GravitySystempara procesarlo.

La conclusión es que cuanto más desacoplado su Componentsson, más extensible la Entitieshabrá cuando se utiliza Systems.

Editar: hizo la última declaración más clara.

Editar: Ok, he estado trabajando en mi propio sistema y llegué a esta conclusión. Un ejemplo para dividir la posición y la velocidad es que manipular la velocidad hace que la posición cambie con un sistema de movimiento. Como resultado, un 'InputMovementSystem' no necesita una posición para hacer que el jugador se mueva de la entrada del usuario porque el sistema de movimiento recogerá los cambios en la velocidad para aplicar a la posición. De acuerdo, todavía funcionaría bien unirlos, pero ese es un ejemplo de por qué no es necesario que lo sean.


Hace poco leí una publicación de blog que decía algo como esto:

"Si tiene datos que se pueden agrupar con 2 componentes diferentes, es mejor crear un tercer componente con esos datos".

Dan H.
fuente