Comment puis-je faire des attaques de bons gars seulement frapper les méchants et vice versa?

11

Mon jeu a différents types de bons et différents types de méchants. Ils tireront tous des projectiles l'un sur l'autre, mais je ne veux pas que des dommages collatéraux accidentels se produisent pour l'un ou l'autre alignement. Donc, les méchants ne devraient pas pouvoir frapper / endommager d'autres méchants et les bons ne devraient pas pouvoir frapper / endommager d'autres bons.

La façon dont je pense à résoudre ce problème est de faire en sorte que l' Unitinstance (c'est javascript, btw), ait une alignmentpropriété qui peut être soit goodou bad. Et je ne laisserai la collision se produire que si le

class Attack

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

C'est du pseudo-code, bien sûr.

Mais je pose cette question parce que j'ai l'impression qu'il pourrait y avoir une façon beaucoup plus élégante de concevoir cela en plus d'ajouter encore une autre propriété à ma Unitclasse.

Daniel Kaplan
la source
5
Le filtrage est l'approche typique ici. C'est essentiellement ce que vous avez décrit. Il y a aussi des couches. Deux couches, mauvaise couche et bonne couche. Des projectiles de méchants sont tirés dans la bonne couche et vice versa.
MichaelHouse
@ Byte56 Pouvez-vous élaborer sur ce concept de "couche"? Ou au moins un lien vers quelque chose à ce sujet? Je n'en ai jamais entendu parler auparavant.
Daniel Kaplan
Ce sont essentiellement des «mondes» différents. Tous les objets d'un calque interagissent entre eux, mais n'interagissent avec aucun autre calque. Cela peut être fait avec des balises (comme le filtrage) ou par des jeux de données totalement différents pour chaque couche.
MichaelHouse
3
En un mot, c'est le regroupement. Regroupez les bonnes balles et vérifiez uniquement les collisions avec les méchants. Flixel a un concept comme celui-ci.
ashes999
3
Une note de conception épineuse: voulez-vous que les tirs de `` tir ami '' frappent mais ne causent aucun dommage, ou voulez-vous qu'ils ignorent complètement les alliés, les traversant éventuellement pour frapper les ennemis à la place?
Steven Stadnicki

Réponses:

6

Filtrage par collision

Une situation plus robuste qui évolue en plusieurs couches consiste à utiliser le filtrage, ce qui n'est pas la même chose que le regroupement.

Cela fonctionne mieux en donnant à chaque objet 2 masques de bit .

Category
Mask

Et ne déclenchez une collision que si ce qui suit est vrai.

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

Il est plus facile de définir par défaut le masque sur 0xFFFF, ce qui entraîne sa collision avec tout. Et par défaut la catégorie à 0x0001. les objets entreront en collision avec les catégories du masque des autres s'il y aura une collision.

Une autre façon de penser est que chaque objet a un type et une liste de tous les types avec lesquels il peut entrer en collision. Il n'y a collision que lorsque deux objets entrent en collision les uns avec les autres. Vous pourriez avoir le même comportement en ayant une liste d'énumérations au lieu d'un masque mais un masque dans un ordre de grandeur plus rapide.

Scénario que vous décrivez

J'aime profiter des énumérations dans cette situation.

Alors disons que oui.

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

Balle tirée par un bon gars

 Category = Bullet
 Mask = BadGuy | GlassWall

Bons gars

 Category = GoodGuy
 Mask = All

Méchants

 Category = BadGuy
 Mask = All

Ce qui se traduit ci-dessous quand une balle tirée par un bon gars frappe un autre bon gars.

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

Mais cela frappera les méchants.

(All & BadGuy) != 0 && <- Passes
(BadGuy & (BadGuy | GlassWall)) != 0; <-- Passes
ClassicThunder
la source
Pourriez-vous expliquer cela conceptuellement au lieu de l'expliquer à un niveau de détail peu arithmétique?
Daniel Kaplan
@tieTYT assurez-vous de vérifier à nouveau dans 5 minutes
ClassicThunder
2

J'ai eu le même problème sur mon projet actuel (en Java). Après quelques essais, il est résolu en créant quatre listes. Cette solution est créée en Java et pour un jeu 2D mais devrait également fonctionner, de manière similaire, 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
       {...}
}

pseudo-code

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

pseudo-code, idem pour la classe Bullets

Ce n'est peut-être pas la solution la meilleure ou la plus rapide, mais cela vous aidera pour le moment. Je suis désolé de ne pas pouvoir vous proposer de solution en JavaScript mais j'espère pouvoir vous aider

Au fait, mon anglais n'est pas le meilleur mais j'espère que vous pourrez suivre mon explication

Jonniy
la source