Sistema de componentes de la entidad: ¿cómo implementar la transformación de un objeto?

11

Al diseñar un sistema de componente de entidad para mi motor, me encontré con un pequeño inconveniente en la forma de almacenar y recuperar un tipo particular de componente.

Primero, permítanme aclarar un poco la terminología que usaré en esta pregunta:

  • Llamo a " Componente " una estructura de datos que almacena datos relevantes para un sistema en particular.
  • Llamo " Sistema " a una agregación de métodos y estructuras de datos que hace uso de Componentes para actualizar el estado / interfaz del juego con el usuario.
  • Una " Entidad " es básicamente una identificación utilizada para recuperar componentes específicos y modificar sus datos en la lógica del juego.

Cada sistema posee una matriz (mapeada por ID) de su tipo de Componente (Ej. Física-> Componente Físico, AI-> Componente AIC, Representación-> Componente de Representación), para que pueda iterar eficientemente sobre los datos.

Sin embargo, no todos los componentes pertenecen específicamente a un sistema. Por ejemplo, un componente Transformar almacena la posición, rotación y escala de un objeto. Es una de las partes más importantes de una entidad (Unity la hace obligatoria, incluso), ya que es utilizada por muchos sistemas, por ejemplo, física, inteligencia artificial, renderización, etc.

Este es más o menos el problema que estoy enfrentando. Dado que muchos otros sistemas usan Transform, ¿cómo debo hacer para recuperar uno para cada Componente? Una posible solución que veo es hacer que cada componente almacene su propia ID de entidad. Sería fácil recuperar cualquier componente como este, pero no sería tan eficiente, y también iría en contra del concepto de un Componente como un paquete de datos aislado e independiente, que no conoce ningún otro.

¿Hay una manera adecuada de resolver este problema? ¿Transformar debería ser incluso un componente?

CRefice
fuente
3
+1 para "Primero, permítanme aclarar un poco la terminología que usaré en esta pregunta:"
Vaillancourt
Me encantaría ver este tipo de preguntas más en este sitio. +1
S. Tarık Çetin
Simplemente almacene todos los componentes como variables globales
Miles Rout

Respuestas:

2

Esta es una pregunta bastante amplia, cuya respuesta depende en gran medida de su arquitectura. Sin embargo, intentaré darle una respuesta general.

Sus sistemas de física y renderización ciertamente requerirán la transformación, sin embargo, el sistema de IA no lo hará. Por lo tanto, tiene sentido encapsular la transformación en su propia clase de componente. Todos estos sistemas interesados ​​usarían los mismos datos, por lo tanto, tiene sentido que la entidad tenga un puntero al objeto de transformación, o una identificación para un objeto de transformación almacenado en otro lugar.

Si elige la última solución, cada sistema que esté interesado en una transformación requerirá acceso a donde sea que esté almacenado el objeto de transformación.

Si elige el primero, todo lo que debe hacer cada sistema es acceder a la entidad misma y solicitar la transformación.

En el primer caso, el problema se convierte en cómo otorgar acceso al almacenamiento para transformaciones en cada sistema, sin romper las reglas de OOP, si le importan tales cosas.

El último caso no tiene tales problemas, pero requiere cambiar el diseño de su objeto de entidad para almacenar punteros a objetos en lugar de identificadores de objetos componentes.

Mi preferencia personal es diseñar la clase de entidad para almacenar punteros a objetos componentes, ya que simplifica muchos problemas de diseño. De esta manera, cada sistema que requiere una transformación puede solicitarlo a la entidad e ignorarlo si no lo hace. Sin embargo, esto conlleva una sobrecarga computacional inherente a los punteros, que es el costo de las fallas de caché.

Eche un vistazo a esta Descripción general de ECS para obtener más información al respecto.

Al final del día, depende de usted decidir qué es más importante para usted: facilidad de desarrollo o rendimiento.

Finalmente, quisiera señalar que su pregunta es un excelente ejemplo de las preguntas de diseño en las que piensan los defensores de ECS, y no existe una solución definitiva de bala de plata.

Ian Young
fuente
Gracias por sus sugerencias Sin embargo, tengo una pregunta: ¿por qué el sistema de IA no necesitaría la posición de un objeto?
CRefice
Está confundiendo la posición (vector de 3 flotadores) con una traducción (matriz de transformación construida a partir de un vector de posición). Una matriz de transformación se construye a partir de traslación, rotación y transformaciones de escala. Esta es mucha más información de la que necesitaría un sistema de IA, aunque ciertamente podría extraerle el vector de posición. Sin embargo, personalmente, separaría la posición, la orientación y los tamaños en su propio componente, y los usaría para crear y actualizar la Transformación.
Ian Young
@IanYoung Separarlos podría hacer más daño que bien, potencialmente si encuentra que necesita una posición y orientación juntos con más frecuencia que la posición u orientación por separado. En ese caso, colocar atributos de datos de posición y orientación en un solo componente puede mejorar el rendimiento de la memoria caché.
Naros
1
Prefiero combinar los tres, la posición, la orientación y la escala en un solo componente y, en caso de que un subsistema específico necesite solo una posición u orientación, recomendaría duplicar los datos y sincronizarlos en puntos claramente definidos en el ciclo del juego. .
Naros
@Naros sí, esto es lo que quise decir: dos componentes, Transformar y (en mi marco) SpatialData, que contiene posición, velocidad, orientación y velocidad angular. La posición y orientación se utilizan para construir y actualizar la transformación.
Ian Young