Muchas fuentes de movimiento en un sistema de entidad.

9

Soy bastante nuevo en la idea de los sistemas de entidades, después de haber leído un montón de cosas (lo más útil, este gran blog y esta respuesta ).

Aunque tengo algunos problemas para entender cómo algo tan simple como poder manipular la posición de un objeto por un número indefinido de fuentes.

Es decir, tengo mi entidad, que tiene un componente de posición. Luego tengo algún evento en el juego que le dice a esta entidad que se mueva una distancia dada, en un momento dado.

Estos eventos pueden ocurrir en cualquier momento y tendrán diferentes valores para la posición y el tiempo. El resultado es que se combinarían entre sí.

En una solución OO tradicional, tendría algún tipo de MoveByclase, que contiene la distancia / tiempo, y un conjunto de aquellos dentro de mi clase de objeto de juego. Cada cuadro, iteraría a través de todo MoveBy, y lo aplicaría a la posición. Si a MoveByha alcanzado su tiempo de finalización, retírelo de la matriz.

Con el sistema de entidades, estoy un poco confundido sobre cómo debería replicar este tipo de comportamiento.

Si hubiera solo uno de estos a la vez, en lugar de poder combinarlos, sería bastante sencillo (creo) y se vería algo así:

PositionComponent que contiene x, y

MoveByComponent que contiene x, y, time

Entityque tiene tanto a PositionComponentcomo aMoveByComponent

MoveBySystemque busca una entidad con estos dos componentes, y añade el valor de MoveByComponentla PositionComponent. Cuando timese alcanza, elimina el componente de esa entidad.

Estoy un poco confundido sobre cómo haría lo mismo con muchos movimientos.

Mis pensamientos iniciales son que tendría:

PositionComponent, MoveByComponentlo mismo que arriba

MoveByCollectionComponentque contiene una matriz de MoveByComponents

MoveByCollectionSystemque busca una entidad con a PositionComponenty a MoveByCollectionComponent, iterando a través de la MoveByComponents dentro de ella, aplicando / eliminando según sea necesario.

Supongo que este es un problema más general, de tener muchos de los mismos componentes y querer que un sistema correspondiente actúe sobre cada uno. Mis entidades contienen sus componentes dentro de un hash de tipo de componente -> componente, por lo que estrictamente tienen solo 1 componente de un tipo particular por entidad.

  1. ¿Es esta la forma correcta de ver esto?

  2. ¿Debería una entidad solo tener un componente de un tipo dado en todo momento?

Pegajoso
fuente
1
¿Suena como si la MoveByfuncionalidad fuera solo una velocidad? Parece que estás en el camino correcto. Para su segunda pregunta, hay muchas implementaciones diferentes de sistemas de entidad / componente. El que se describe en mi respuesta que vinculó solo tendría un componente de un tipo dado.
MichaelHouse
Más o menos, pero la diferencia es que esta velocidad solo es válida de una vez a otra, y muchas de ellas pueden combinarse a la vez. Creo que solo necesitaba un poco de tranquilidad, he sido estricto (anal, casi) OO para mis juegos en el pasado, que años después en el mismo proyecto, ha paralizado nuestra velocidad de producción, y este es un territorio extrañamente desconocido;) . Por cierto, la gran respuesta en la otra publicación ayudó a aclarar algunas cosas
Sticky
Lo hago así: tengo PlayerInputComponent y AIInputComponent (o sistemas) que le indicarán a MobileBehaviorComponent que al hacer clic en el teclado o en AI pensando que el móvil debe moverse a algún lado, MobileBehaviorComponent almacenará que debe moverse a algún lugar (tiene FSM dentro para acciones móviles) y algún sistema lo moverá. Su granularidad es demasiado, con componentes de nivel superior, como Transformar, Modelo, Luz, Mob, todo funciona igual de bien. Además, nunca tuve que eliminar componentes, pienso en ellos más como algo que describe el objeto del juego para que no pueda desaparecer.
Kikaimaru
Este ejemplo particular de MoveBy fue solo un ejemplo. La pregunta era más sobre cómo se combinan las cosas de esa manera. Si necesito decir específicamente 'mover por x = 5 e y = 6 en 5 segundos' 'mover por x = 10 y = 2 en 10 segundos', al mismo tiempo, ¿es así como lo haría?
Sticky
¿Qué quieres decir con "compuesto juntos"? ¿Te gusta sumar velocidades? Entonces, ¿si se complicara move x by 10 in 2 secondsy move x by -10 in 2 secondsla entidad se quedaría perfectamente quieta?
Tom Dalling

Respuestas:

6

Para su escenario, generalmente agregamos tres componentes a un objeto de juego:

  1. TransformComponent (posición, orientación, escala)
  2. Componente de velocidad (velocidad, dirección)
  3. ControllerComponent

Cuando los objetos del juego necesitan algún tipo de funcionalidad de IA, como moverse a lo largo de una ruta como la describiste, asignamos un AIController a su lista de componentes. Los controladores AIC realmente no son más que un contenedor que da paso a un árbol de comportamiento. El árbol de comportamiento es donde diseñamos la funcionalidad real que queremos que realice el objeto del juego, como por ejemplo:

BehaviorTree* tree(new SequentialNode());
tree->addChild(new MoveToNode(x,y,z));
tree->addChild(new WaitNode(30));
tree->addChild(new MoveToNode(a,b,c));
tree->addChild(new WaitNode(30));
gameObject->addComponent(new AIController(tree));

El subsistema AI gestiona los controladores AIC y, por lo tanto, el subsistema marca el controlador, que a su vez da pasos al Árbol de comportamiento. MoveToNode () mira la posición / orientación actual, calcula un vector de dirección y velocidad a donde desea moverse en función de sus argumentos de constructor y establece los valores en el componente de velocidad. El sistema de movimiento es responsable de leer los componentes del movimiento con valores y aplicar la física, actualizando así la posición / orientación en consecuencia.

El código anterior simplemente mueve un objeto del juego desde la ubicación de generación a x, y, z en el espacio mundial, luego espera un mínimo de 30 segundos, luego mueve el objeto del juego a la ubicación a, b, c y luego espera otros 30 segundos. Una vez que finaliza la espera, la secuencia de comportamiento ha finalizado, por lo que se repite desde el principio.

Esto le permite definir fácilmente cualquier funcionalidad de AI que necesite, todo autónomo en el subsistema de AI con un impacto mínimo en su subsistema de entidad. También le permite mantener su lista de componentes del sistema de entidad sin demasiada granularidad.

Naros
fuente
1

Una opción es agregar controladores a su diseño. Las entidades poseen datos para representar la posición (en el caso de mi motor, también tienen datos que recuerdan las posiciones anteriores, por lo que puedo conocer el vector de velocidad y si se están moviendo o teletransportando), pero no saben nada sobre física o AI. Los controladores mueven entidades y puede tener muchos controladores que afectan a la misma entidad o un controlador que afecta a varias entidades.

Por ejemplo: cree una clase de controlador base con un método run (), o si no le gusta el nombre llámelo think (), update () o tick (). Luego hereda de él y crea un MoveController, NPCController, PlayerInputController (para la entidad del jugador), PhysicController; entonces implementa el método run (). Pondría su MoveByComponent en MoveController y no en Entity.

Estos controladores pueden ser instanciados por cada entidad si contienen datos específicos de una entidad. Se pueden destruir o restablecer para su reutilización posterior. También puede usar un controlador para mover un grupo de entidades, en un juego RTE, por ejemplo, si necesita mover varias unidades como grupo, tener un controlador por cada unidad puede afectar el rendimiento del juego, entonces simplemente puede asignar todas las unidades a un GroupController o LegionController y dejar que mueva las unidades como parte de un grupo organizado. Cuando peleas, si el juego permite el comportamiento individual de la unidad, y probablemente la mayoría de los juegos lo hagan, tendrás que cambiar a un UnitController, pero es mejor hacerlo solo cuando sea necesario que desde el principio.

En mi juego en desarrollo tengo un MoveController que mueve entidades siguiendo una ruta, existe un MoveController para cada NPC y el personaje del jugador. Ocasionalmente se crea uno para cajas o rocas que el jugador puede empujar. El PhysicController, solo una instancia, que verificará las posiciones de todas las entidades asignadas a él, si alguna entidad está colisionando con otra entidad asignada, se calcula la posición resultante de ambos (en realidad hace más que eso, pero se entiende la idea). El NPCController es la IA, una instancia por NPC. Comprueba la situación del NPC y decide dónde moverse, luego empuja el camino hacia un MoveController, que realmente mueve el NPC. Los controladores tienen una prioridad, por lo que puedo determinar de antemano su orden, el PhysicController es el último en ejecutarse.

Abogo por los controladores, pero no es la única opción "correcta". Por ejemplo, recuerdo una interfaz Entity en el motor Cafu que tiene el método think () en la Entidad misma, el usuario de la clase debe heredar de Entity e implementar think (), recuerdo una clase derivada llamada CompanyBot (que viene con el ejemplo juego) que hacen un poco de verificación de colisión en ese método, como se llama "pensar", podemos suponer que también se espera que el código AI esté allí. Mientras que el motor NeoAxis (la última vez que lo examiné) tiene inteligencia artificial y física separadas de las entidades.

Existe un patrón de controlador que he escuchado. Tal vez deberías buscarlo, y eso probablemente no sea exactamente de lo que estoy hablando aquí, pero también parece una buena solución.

Hatoru Hansou
fuente
Ese es básicamente el diseño OO que ya tenemos en este momento. Una entidad, con derivados (personaje, monstruo), etc., he estado liderando un equipo de nosotros que hemos estado trabajando en este juego a tiempo completo durante casi 2 años, y con todo el mundo cambiando las cosas a voluntad, se ha vuelto horrible, horrible. codebase, y está comenzando a tomar un tiempo embarazosamente largo para que se envíen nuevas funciones. La idea Sistema Entidad parece ser exactamente lo que estoy buscando, así, mientras que su respuesta no es muy relevante, usted debe leer sobre los enlaces en la parte superior de la pregunta a sí mismo, ver si pueden ayudar a salir :)
Sticky
@Sticky Tengo que admitir que el Node System plus Entity hecho de componentes es una forma inteligente de representar los diferentes sistemas necesarios que el enfoque de mis controladores sugeridos que es como una versión menos evolucionada. Realmente no necesitas mi respuesta después de todo.
Hatoru Hansou
Sin preocupaciones. El modo OO tiene sus ventajas, pero las cosas se ponen feas, rápido
Sticky