Si dos objetos interactúan, ¿qué contiene el código de interacción?

28

Piense en una bala y un enemigo, o el jugador y el piso. Si estos objetos interactúan, ¿qué contiene el código de interacción?

ThatOneGuy
fuente
2
¿Interactuar de qué manera? ¿Te refieres a la detección de colisión? Si es así, lo más probable es que implemente una clase de detección de colisión y un administrador de resolución de colisión.
CaptainRedmuff
En parte sí, estoy interesado tanto en la colisión como en lo que sucede después de la colisión. ¿La bala comprueba si está cerca del enemigo o al revés? ¿Y qué sucede después de la colisión? ¿Puede un objeto bala decirle a un objeto enemigo que ha sido alcanzado? Como puede ver, estoy bastante confundido acerca de todo el asunto, y hace que el código sea muy difícil de leer.
ThatOneGuy

Respuestas:

23

TL; DR:

Sus objetos de juego no se conocen entre sí, ni realizan comprobaciones contra otros objetos. Crea un patrón de detección de colisión y resolución de colisión que verifica los objetos del juego y realiza las acciones apropiadas para simular la física del juego.

Lo bueno

De intentos anteriores de escribir la detección de colisión y leer este libro , hay dos etapas para la detección de colisión y la resolución de colisión. La primera etapa (detección de colisión) es un pase temprano en el que determina si dos objetos pueden tener una colisión potencial. En caso de que dos objetos formen una colisión potencial, entonces pasa estos objetos a la segunda etapa (resolución de colisión) para ejecutar una verificación más fina contra los objetos e intentar resolver la colisión.

En algún lugar de su motor / juego, tendrá una variedad de todos los objetos en su mundo. En cada cuadro, recorrerá la matriz y verificará cada objeto contra cualquier otro objeto con un simple cuadro de límite / detección de colisión de esfera.

Pseudocódigo:

dectectCollisions(objects)
{
    for(objectA in objects)
    {
        for(objectB in objects)
        {
            if(objectA != objectB) //ignore self
            {
                if(BoundingSpheresIntersect(objectA, objectB))
                {
                    collisionResolver.addObjects(objectA, objectB);
                }
            }
        }
    }
}

Este tipo de bucle es bastante ineficiente, pero deja margen para mejorar mediante el uso de la partición espacial como salida anticipada para objetos que se garantiza que están demasiado separados para colisionar.

Después de verificar los dos objetos para detectar una posible colisión (es decir, ambos objetos están lo suficientemente cerca como para colisionar), los objetos se pasan para realizar una rutina de detección de colisión más precisa.

Imagine que tiene dos polígonos de formas y tamaños aleatorios que están lo suficientemente cerca como para potencialmente cruzarse pero no debido a su geometría:

Imagen encontrada a través de google

Usando esferas de delimitación, estos dos objetos crearían un falso positivo para una posible colisión. Aquí es donde realizarías un pase más completo para determinar si los dos objetos se cruzan realmente.

Una vez que haya encontrado una verdadera colisión, su paso de resolución de colisión realizaría la acción adecuada para resolver los objetos aplicando fuerzas o momentos dependiendo de la granularidad y las necesidades de la física de su juego.

Con esto en mente, puede abstraer todo el proceso de detección y resolución de colisiones para que sus objetos no necesiten saber nada el uno del otro, ni el proceso requerido para determinar y resolver las colisiones. Las dos clases / gerentes que manejan esto para usted solo necesitan conocer las propiedades básicas de cada objeto para realizar una verificación rápida y sucia de colisiones y luego una verificación más exhaustiva si fuera necesario.

CaptainRedmuff
fuente
2
En particular, el patrón de diseño del Mediador sería apropiado. El patrón Observador sería una buena alternativa, que tiene una intención muy diferente. Puede obtener un resumen bastante bueno de ellos en esta publicación de Stackoverflow .
kurtzbot
12

Una forma en que Unreal Engine 3 lo maneja:

La bala recibe un mensaje de colisión que dice que golpeó algo, con un argumento que le dice qué golpeó. Luego puede llamar a objectHit.takeDamage (self). El objetivo luego recibe el mensaje TakeDamage, con un puntero a la cosa que lo golpeó, y toma la acción adecuada.

Personalmente, me gusta este enfoque porque significa que la bala puede tomar acciones especiales (como hacer algún tipo de efecto de explosión dependiendo del tipo de cosa golpeada) y el objetivo puede tomar acciones especiales dependiendo del tipo de bala.

También es posible que la viñeta sepa lo que hace a los objetivos y puede llamar a la función, como objectHit.freeze (self). Entonces el objetivo sabe que fue golpeado por algo que lo congela, y qué tipo de objeto era.

EDITAR: Esta respuesta se entiende como una imagen general de cómo puede funcionar, ya que probablemente no esté trabajando con UE3. :)

Almo
fuente
10

Thief hizo esto muy bien en Dark Engine con fuentes y receptáculos. Un objeto podría tener ambas propiedades, con diferentes tipos. Por ejemplo, una flecha de agua tendría una fuente para WaterStim en contacto. Una explosión tendría un AoE FireStim.

Cuando una flecha de agua golpea un objeto, el objeto objetivo busca en sus Receptrones cualquier cosa que busque un WaterStim con los valores de intensidad apropiados. Luego ejecuta cualquier comando asociado con él (en este caso, gira una antorcha encendida a una antorcha apagada y emite una nube de humo).

Dado que se utiliza el mismo motor en SystemShock2, así es como se manejan todos los diferentes tipos de daño, las diferentes balas tienen un conjunto de Stims diferente y los diferentes monstruos tienen Receptrones para los diferentes tipos de Stim y hacen un daño igual a 1 *, 2 *, 1 / 2 la intensidad dependiendo de si el tipo de munición es "super efectivo" o no.

Parecía un sistema muy flexible, ya que podía agregar fuentes y receptáculos a los objetos en el editor de niveles (para hacer una puerta única que se abre si es golpeada por el fuego, por ejemplo). Mientras que también podría decirle a un receptrón que "envíe el guión mensaje "si el objeto tenía scripts especiales asociados a él.

¡Lo que no quiere hacer es codificar una matriz de interacción nXn de todos los objetos posibles que colisionan con todos los objetos posibles! Al generalizar las interacciones a través de mensajes estandarizados, simplifica el proceso.

Mella
fuente
Desde el punto de vista de las secuencias de comandos, este enfoque parece el más flexible y el más expresivo. Muy genial.
drhayes
-2

Una solución es mantener los contenedores de balas y jugadores en clases separadas, y luego tener la función main () que mantiene el ciclo de cuadro responsable de la interacción.

tp1
fuente