Después de leer algunos documentos sobre el sistema de entidad-componente, decidí implementar el mío. Hasta ahora, tengo una clase World que contiene las entidades y el administrador del sistema (sistemas), la clase Entity que contiene los componentes como std :: map y algunos sistemas. Tengo entidades como std :: vector en World. No hay problema hasta ahora. Lo que me confunde es la iteración de entidades, no puedo tener una mente clara sobre eso, así que todavía no puedo implementar esa parte. ¿Debería cada sistema tener una lista local de entidades que les interesan? ¿O debería simplemente iterar a través de las entidades en la clase Mundial y crear un bucle anidado para iterar a través de los sistemas y verificar si la entidad tiene los componentes en los que está interesado el sistema? Quiero decir :
for (entity x : listofentities) {
for (system y : listofsystems) {
if ((x.componentBitmask & y.bitmask) == y.bitmask)
y.update(x, deltatime)
}
}
pero creo que un sistema de máscara de bits bloqueará un poco la flexibilidad en caso de incrustar un lenguaje de script. O tener listas locales para cada sistema aumentará el uso de memoria para las clases. Estoy terriblemente confundido
fuente
Respuestas:
Es una compensación tradicional de espacio-tiempo .
Si bien iterar a través de todas las entidades y verificar sus firmas es directo al código, puede volverse ineficiente a medida que crece su número de sistemas: imagine un sistema especializado (que sea una entrada) que busque su entidad de interés probablemente única entre miles de entidades no relacionadas .
Dicho esto, este enfoque aún puede ser lo suficientemente bueno según tus objetivos.
Sin embargo, si le preocupa la velocidad, por supuesto, hay otras soluciones a considerar.
Exactamente. Este es un enfoque estándar que debería brindarle un rendimiento decente y es razonablemente fácil de implementar. La sobrecarga de memoria es insignificante en mi opinión, estamos hablando de almacenar punteros.
Ahora, cómo mantener estas "listas de interés" puede no ser tan obvio. En cuanto al contenedor de datos,
std::vector<entity*> targets
la clase interna del sistema es perfectamente suficiente. Ahora lo que hago es esto:Cada vez que agrego un componente a una entidad:
iterar a través de todos los sistemas del mundo y si hay un sistema cuya firma no coincide con la firma actual de la entidad y sí coincide con la nueva firma, resulta obvio que deberíamos empujar hacia atrás el puntero a nuestra entidad allí.
Eliminar una entidad es completamente análogo, con la única diferencia que eliminamos si un sistema coincide con nuestra firma actual (lo que significa que la entidad estaba allí) y no coincide con la nueva firma (lo que significa que la entidad ya no debería estar allí). )
Ahora puede estar considerando el uso de std :: list porque eliminar del vector es O (n), sin mencionar que tendría que cambiar una gran cantidad de datos cada vez que elimine del medio. En realidad, no tiene que hacerlo, ya que no nos importa procesar el pedido en este nivel, solo podemos llamar a std :: remove y vivir con el hecho de que en cada eliminación solo tenemos que realizar O (n) búsqueda de nuestro entidad a ser eliminada.
std :: list le daría O (1) eliminar pero en el otro lado tiene un poco de sobrecarga de memoria adicional. También recuerde que la mayoría de las veces procesará entidades y no las eliminará, y esto seguramente se hace más rápido usando std :: vector.
Si usted es muy crítico con el rendimiento, puede considerar incluso otro patrón de acceso a datos , pero de cualquier manera mantiene algún tipo de "listas de interés". Sin embargo, recuerde que si mantiene su API de Entity System lo suficientemente abstraída, no debería ser un problema mejorar los métodos de procesamiento de entidades de los sistemas si su tasa de fotogramas disminuye debido a ellos, por lo tanto, por ahora, elija el método que le resulte más fácil de codificar. luego perfile y mejore si es necesario.
fuente
Hay un enfoque que vale la pena considerar donde cada sistema posee los componentes asociados a sí mismo y las entidades solo se refieren a ellos. Básicamente, su
Entity
clase (simplificada) se ve así:Cuando dice un
RigidBody
componente adjunto a unEntity
, lo solicita de suPhysics
sistema. El sistema crea el componente y permite que la entidad mantenga un puntero sobre él. Su sistema entonces se ve así:Ahora, esto puede parecer un poco intuitivo al principio, pero la ventaja radica en la forma en que los sistemas de entidades componentes actualizan su estado. A menudo, iterará a través de sus sistemas y solicitará que actualicen los componentes asociados.
La fortaleza de tener todos los componentes que posee el sistema en la memoria contigua es que cuando su sistema itera sobre cada componente y lo actualiza, básicamente solo tiene que funcionar
No tiene que iterar sobre todas las entidades que potencialmente no tienen un componente que necesitan actualizar y también tiene un potencial para un rendimiento de caché muy bueno porque todos los componentes se almacenarán contiguamente. Esta es una, si no la mayor ventaja de este método. A menudo tendrá cientos y miles de componentes en un momento dado, también podría intentar ser lo más eficiente posible.
En ese punto, sus
World
únicos bucles a través de los sistemas y los llamaupdate
sin necesidad de iterar entidades también. Es (en mi humilde opinión) un mejor diseño porque las responsabilidades de los sistemas son mucho más claras.Por supuesto, hay una infinidad de diseños de este tipo, por lo que debe evaluar cuidadosamente las necesidades de su juego y elegir el más apropiado, pero como podemos ver aquí, a veces son los pequeños detalles de diseño los que pueden marcar la diferencia.
fuente
En mi opinión, una buena arquitectura es crear una capa de componentes en las entidades y separar la administración de cada sistema en esta capa de componentes. Por ejemplo, el sistema lógico tiene algunos componentes lógicos que afectan a su entidad y almacena los atributos comunes que se comparten con todos los componentes de la entidad.
Después de eso, si desea administrar los objetos de cada sistema en diferentes puntos, o en un orden particular, es mejor crear una lista de componentes activos en cada sistema. Todas las listas de punteros que puede crear y administrar en los sistemas son menos de un recurso cargado.
fuente