Manera adecuada de manejar la destrucción de las entidades del juego.

10

Imagine un mundo de juegos en el que cargas y cargas de entidades se cargan dinámicamente todo el tiempo, tal vez lo representaría como una lista de entidades, pero ¿qué pasa con eliminarlas?

Mientras que al agregar, podría estar retrasando la nueva entidad, podría tener la necesidad de eliminar cualquier parte del contenedor. Para evitar buscar el elemento para encontrar su posición de eliminación, ¿qué opciones tengo?

Pensé que podría almacenar la identificación de la entidad como su posición en el contenedor, creando una ruta para la eliminación directa, pero ¿eso no generaría algún tipo de "trastorno" de dependencia mutua?

Sé que la forma correcta sería algo como List.RemoveAt (whereToRemove); pero ¿y si solo la entidad sabe cuándo debe morir?

¿O solo me falta algo y un contenedor de lista sabría cuándo se destruye un objeto y reduce su propio tamaño?

Grimshaw
fuente

Respuestas:

10

Aquí están tus condiciones:

  • Otros objetos aún pueden depender de su entidad eliminada, después de que se elimine.

  • Solo desea que la entidad especifique su propia eliminación.

No puedes tener ambos. ¿Por qué? Debido a que el código en un nivel más alto que su propia entidad (vea los ejemplos a continuación) decide cuándo debe usarse esa entidad. En consecuencia, solo el código en ese mismo nivel puede determinar si su entidad es apta para su eliminación o no.

Sin embargo , lo que puede suceder es que la entidad puede solicitar su propia eliminación, activando un evento que el código de nivel superior está escuchando. Ese nivel superior luego almacena esta solicitud de eliminación en una lista.


Ejemplo 1: sin eventos

Estás comprobando colisiones entre entidades en tu mundo. Esto se maneja más arriba, generalmente en el ciclo principal del juego, que compara a cada entidad entre sí. En este ejemplo específicamente, cuando una entidad colisiona con otra, solo la lógica interna de esa entidad puede determinar cuánto daño ha sufrido y si ha "caducado" o no. Entonces, sigamos el flujo lógico para colisiones en las que tiene cuatro entidades en su mundo, A, B, C y D. A es nuestra entidad que nos preocupa.

Verificamos A para colisión con B. Hay una colisión. A recibe daño 50%.

Verificamos A para colisión con C. Hay una colisión. A recibe daño 50%. Como el daño llega a 0, A determina que ha "muerto". Se elimina de la lista.

Verificamos A para colisión con D. No habría habido colisión, pero nunca llegarás tan lejos: obtienes una excepción de tiempo de ejecución porque tu lista de entidades se ha modificado en medio de una operación de viaje.

Ejemplo 2: con eventos

La misma configuración que antes.

Verificamos A para colisión con B. Hay una colisión. A recibe daño 50%.

Verificamos A para colisión con C. Hay una colisión. A recibe daño 50%. Como el daño llega a 0, A determina que ha "muerto". Dispara un evento al código de gestión de la entidad para decir: "Quitarme lo antes posible". El código de gestión de la entidad examina la referencia de la entidad enviada como parte del evento y almacena esa referencia en una lista de entidades que se eliminarán.

Verificamos A para colisión con D. No hay colisión, y la verificación funciona bien.

Ahora, al final de la iteración del bucle del juego actual , recorra la lista de entidades que se eliminarán y elimine cada una de ellas de su lista de entidades principales.


Puedes ver cómo esto evita el problema por completo. No necesita usar eventos, puede usar señales u otra cosa, pero el principio es el mismo: no elimine entidades hasta que pueda hacerlo de manera segura. La otra cara de este enfoque, para mantener las cosas limpias y ordenadas, es hacer lo mismo con las entidades para agregar: asegúrese de mantener referencias a ellas y solo agréguelas al comienzo de la próxima iteración del bucle del juego.

Por último, no olvide eliminar las listas para eliminar y agregar, cada vez que las use para realizar adiciones / eliminaciones en su lista de entidades principal.

PD. No tenga miedo de buscar en su lista principal para realizar mudanzas individuales. Es parte integrante de la gestión de entidades, e incluso las listas masivas tienden a ser muy rápidas de recorrer, después de todo, para eso están diseñadas.

Ingeniero
fuente
0

Definitivamente estás buscando un HashMap / HashTable . Una tabla hash es un mapa que hace coincidir una clave con un valor específico. La clave puede ser cualquier cosa (como el ID de la entidad).

Setheron
fuente
0

Supongo que podría usar la idea de puntero inteligente para manejar las asignaciones de negocios por usted, en ese caso no será necesario mantener una lista de todas las entidades dentro de su código.

en algunos casos necesitas una lista para iterar sobre todos los objetos de tu juego. esta lista podría ser simplemente una lista de enlaces donde insertar y eliminar objetos llevará exactamente O (1) tiempo.

incluso para aumentar más tu velocidad, puedes usar una matriz estática (posiblemente un vector). en ese caso, deberá realizar un seguimiento de 2 listas vinculadas dentro del mismo vector, una iterará sobre objetos válidos y otra iterará sobre objetos libres. siempre que el puntero inteligente marque algún lugar para ser eliminado, simplemente elimine ese puntero y agregue su espacio a la lista de espacios libres. y cada vez que agrega alguna entidad, solo necesita eliminar el primer espacio libre, llenarlo con el puntero de entidad y luego agregarlo a la lista de objetos válidos.

Ali1S232
fuente