Como eu faço ataques de mocinho apenas atingem bandidos e vice-versa?

11

Meu jogo tem muitos tipos diferentes de mocinhos e muitos tipos diferentes de bandidos. Todos estarão atirando projéteis um no outro, mas não quero que ocorram danos colaterais acidentais por qualquer alinhamento. Então, bandidos não devem ser capazes de atingir / danificar outros bandidos e bandidos não devem ser capazes de atingir / danificar outros bandidos.

A maneira como estou pensando em resolver isso é fazer com que a Unitinstância (isto é javascript, btw) tenha uma alignmentpropriedade que possa ser um goodou outro bad. E eu só vou deixar a colisão acontecer se o

class Attack

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

Isso é pseudo-código, é claro.

Mas estou fazendo essa pergunta porque tenho a sensação de que pode haver uma maneira muito mais elegante de projetar isso, além de adicionar mais uma propriedade à minha Unitclasse.

Daniel Kaplan
fonte
5
A filtragem é a abordagem típica aqui. Essencialmente, foi o que você descreveu. Também há camadas. Duas camadas, camada ruim e boa camada. Os projéteis de bandidos são disparados para a camada boa e vice-versa.
MichaelHouse
@ Byte56 Você pode elaborar esse conceito de "camada"? Ou pelo menos link para algo sobre isso? Eu nunca ouvi falar disso antes.
Daniel Kaplan
Essencialmente, eles são "mundos" diferentes. Todos os objetos em uma camada interagem entre si, mas não interagem com nenhuma outra camada. Isso pode ser feito com tags (como filtragem) ou com conjuntos de dados totalmente diferentes para cada camada.
MichaelHouse
3
Em uma palavra, é agrupamento. Agrupe boas balas e verifique apenas se há colisão contra bandidos. Flixel tem um conceito como este.
ashes999
3
Uma nota de design bem detalhada: você quer que os tiros de 'tiro amigável' atinjam, mas não causa dano, ou deseja que eles ignorem completamente os aliados, possivelmente passando por eles para atacar os inimigos?
Steven Stadnicki

Respostas:

6

Filtragem de colisão

Uma situação mais robusta e escalável em várias camadas é usar a filtragem, que não é a mesma coisa que agrupar.

Isso funciona melhor dando a cada objeto 2 máscaras de bits .

Category
Mask

E só desencadeie uma colisão se o abaixo for verdadeiro.

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

É mais fácil padronizar a máscara para 0xFFFF, o que resulta em uma colisão com tudo. E padrão a categoria para 0x0001. objetos colidem com as categorias nas outras máscaras, haverá uma colisão.

Outra maneira de pensar é que cada objeto tem um tipo e uma lista de todos os tipos com os quais pode colidir. Somente quando dois objetos colidem com os tipos um do outro é que há uma colisão. Você pode ter o mesmo comportamento tendo uma lista de enumerações em vez de uma máscara, mas uma máscara em uma ordem de magnitude mais rápida.

Cenário que você descreve

Eu gosto de aproveitar enums nesta situação.

Então diga que sim.

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

Bullet baleado por um cara legal

 Category = Bullet
 Mask = BadGuy | GlassWall

Bons homens

 Category = GoodGuy
 Mask = All

Bandidos

 Category = BadGuy
 Mask = All

O que resulta no abaixo, quando um tiro de bala de um cara legal atinge outro cara legal.

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

Mas atingirá bandidos.

(All & BadGuy) != 0 && <- Passes
(BadGuy & (BadGuy | GlassWall)) != 0; <-- Passes
ClassicThunder
fonte
Você se importaria de explicar isso conceitualmente, em vez de explicá-lo em detalhes de baixo nível da aritmética de bits?
Daniel Kaplan
@tieTYT certeza de verificar novamente em 5 minutos
ClassicThunder
2

Eu tive o mesmo problema no meu projeto atual (em Java). Depois de algumas tentativas é resolvido criando quatro listas. Essa solução é criada em Java e para um jogo 2D, mas também deve funcionar, de maneira semelhante, em 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
       {...}
}

pseudo-código

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

pseudo-código, o mesmo para a classe Bullets

Esta pode não ser a melhor ou mais rápida solução, mas ajudará você no momento. Lamento não poder fornecer uma solução em JavaScript, mas espero poder ajudá-lo

A propósito, meu inglês não é o melhor, mas espero que você possa seguir minha explicação

Jonniy
fonte