¿Cómo hago para que los ataques de los buenos solo golpeen a los malos y viceversa?

11

Mi juego tiene muchos tipos diferentes de buenos y muchos tipos diferentes de malos. Todos dispararán proyectiles entre sí, pero no quiero que se produzca ningún daño colateral accidental para ninguna de las alineaciones. Entonces, los malos no deberían poder golpear / dañar a otros malos y los buenos no deberían poder golpear / dañar a otros buenos.

La forma en que estoy pensando en resolver esto es haciendo que la Unitinstancia (esto es javascript, por cierto), tenga una alignmentpropiedad que puede ser goodo bad. Y solo dejaré que ocurra la colisión si el

class Attack

    boolean didAttackCollideWithTarget(target)
        return attack.source.alignment != target.alignment and collisionDetected(attack.source, target)

Este es un pseudocódigo, por supuesto.

Pero hago esta pregunta porque tengo la sensación de que podría haber una forma mucho más elegante de diseñar esto además de agregar otra propiedad a mi Unitclase.

Daniel Kaplan
fuente
55
El filtrado es el enfoque típico aquí. Esencialmente, eso es lo que has descrito. También hay capas. Dos capas, mala capa y buena capa. Los proyectiles de los malos se disparan en la capa buena y viceversa.
MichaelHouse
@ Byte56 ¿Puede elaborar este concepto de "capa"? ¿O al menos un enlace a algo al respecto? Nunca he oído hablar de eso antes.
Daniel Kaplan
Esencialmente son "mundos" diferentes. Todos los objetos en una capa interactúan entre sí, pero no interactúan con ninguna otra capa. Esto se puede hacer con etiquetas (como el filtrado) o con conjuntos de datos totalmente diferentes para cada capa.
MichaelHouse
3
En una palabra, es agrupación. Agrupe las balas buenas y solo verifique la colisión contra los malos. Flixel tiene un concepto como este.
cenizas999
3
Un diseño nitpicky nota: ¿quiere 'fuego amigo' tiros para golpear pero no hacen ningún daño, o quieres que ignoren completamente aliados, posiblemente pasando a través de ellos para golpear enemigos en su lugar?
Steven Stadnicki

Respuestas:

6

Filtro de colisión

Una situación más robusta que se escala en muchas capas es usar el filtrado, que no es lo mismo que agrupar.

Esto funciona mejor al dar a cada objeto 2 máscaras de bits .

Category
Mask

Y solo desencadenará una colisión si lo siguiente es cierto.

(filterA.maskBits & filterB.categoryBits) != 0 &&
(filterA.categoryBits & filterB.maskBits) != 0;

Es más fácil establecer la máscara por defecto en 0xFFFF, lo que hace que choque con todo. Y por defecto la Categoría a 0x0001. los objetos colisionan con las categorías en la máscara de otros habrá una colisión.

Otra forma de pensarlo es que cada objeto tiene un tipo y una lista de todos los tipos con los que puede colisionar. Solo cuando dos objetos colisionan con los tipos entre sí, se produce una colisión. Podría tener el mismo comportamiento al tener una lista de enumeraciones en lugar de una máscara, pero una máscara en un orden de magnitud más rápido.

Escenario que describe

Me gusta aprovechar las enumeraciones en esta situación.

Entonces digamos que tenemos.

enum Categories {
    GoodGuy =           0x0001,
    BadGuy =            0x0002,
    Bullet =            0x0004,
    GlassWall =         0x0008,
    Lazer =             0x0010,
    All =               0xFFFF
};

Bala disparada por un buen chico

 Category = Bullet
 Mask = BadGuy | GlassWall

Chicos buenos

 Category = GoodGuy
 Mask = All

Chicos malos

 Category = BadGuy
 Mask = All

Lo que da como resultado lo siguiente cuando un disparo de bala de un buen tipo golpea a otro buen tipo.

(All & GoodGuy) != 0 && <-- Passes
(GoodGuy & (BadGuy | GlassWall)) != 0; <-- This would fail

Pero golpeará a los malos.

(All & BadGuy) != 0 && <- Passes
(BadGuy & (BadGuy | GlassWall)) != 0; <-- Passes
Trueno clásico
fuente
¿Le importaría explicar esto conceptualmente en lugar de explicarlo con un nivel bajo de detalle de aritmética de bits?
Daniel Kaplan
@tieTYT asegúrese de verificar nuevamente en 5 minutos
ClassicThunder
2

Tuve el mismo problema en mi proyecto actual (en Java). Después de un par de intentos se resuelve creando cuatro listas. Esta solución se creó en Java y para un juego 2D, pero también debería funcionar, de manera similar, en JavaScript

public static main (String [] args)
{
    private List<Bullets> bullets_GoodGuys = new LinkedList <Bullet>(); //List of all bullets fired by good guys
    private List<Bullets> bullets_BadGuys  = new LinkedList <Bullet>(); //List of all bullets fired by bad guys
    private List<Guys> goodGuys  = new LinkedList <Guys>(); //List of all good guys
    private List<Guys> badGuys  = new LinkedList <Guys>();  //List of all good guys

    init();
    ...
    while(game_is_running)
    {
        ... 
        for(int i=0;i>=goodGuys.length;i++)
        {
            for(int j=0;j>=bullets_BadGuys.length;i++)
            {
                if(goodGuys.get(i).getBounding().interacts(bullets_BadGuys.get(i).getBounding()))
                {// If a good guy was hit by a bullet from a bad guy
                    goodGuys.get(i).getDamage();
                    bullets_BadGuys.remove((bullets_BadGuys.get(i));
         }   }   }
       for(...) //same for the bad guys
       {...}
}

pseudocódigo

class Guys
{
   private float xkoordinate;
   private float ykoordinate;
   private BufferedImage look;
   private Rectangle bounding = new Rectangle(xkoordinate,ykoordinate,look.getWith(),look.getHight())
   ...
}

pseudocódigo, igual para la clase Bullets

Puede que esta no sea la mejor solución o la más rápida, pero lo ayudará en este momento. Lamento no poder darte una solución en JavaScript, pero espero poder ayudarte

Por cierto, mi inglés no es el mejor, pero espero que puedas seguir mi explicación

Jonniy
fuente