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?
fuente
Respuestas:
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.
fuente