Wie mache ich Angriffe von Guten, die nur Böse treffen und umgekehrt?

11

Mein Spiel hat viele verschiedene Arten von Guten und viele verschiedene Arten von Bösen. Sie werden alle Projektile aufeinander abfeuern, aber ich möchte nicht, dass bei beiden Ausrichtungen versehentliche Kollateralschäden auftreten. So sollten böse Jungs nicht in der Lage sein, andere böse Jungs zu schlagen / zu beschädigen, und gute Jungs sollten nicht in der Lage sein, andere gute Jungs zu schlagen / zu beschädigen.

Ich denke daran, dies zu lösen, indem ich es so mache, dass die UnitInstanz (dies ist übrigens Javascript) eine alignmentEigenschaft hat, die entweder goododer sein kann bad. Und ich werde nur dann eine Kollision zulassen, wenn die

class Attack

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

Das ist natürlich Pseudocode.

Aber ich stelle diese Frage, weil ich das Gefühl habe, dass es eine viel elegantere Möglichkeit gibt, dies zu entwerfen, als meiner UnitKlasse noch eine weitere Eigenschaft hinzuzufügen .

Daniel Kaplan
quelle
5
Filterung ist hier der typische Ansatz. Im Wesentlichen haben Sie das beschrieben. Es gibt auch Schichten. Zwei Schichten, schlechte Schicht und gute Schicht. Böse Projektile werden in die gute Schicht abgefeuert und umgekehrt.
MichaelHouse
@ Byte56 Können Sie dieses "Ebenen" -Konzept näher erläutern? Oder zumindest auf etwas darüber verlinken? Davon habe ich noch nie gehört.
Daniel Kaplan
Im Wesentlichen sind sie verschiedene "Welten". Alle Objekte in einer Ebene interagieren miteinander, aber nicht mit einer anderen Ebene. Dies kann mit Tags (wie Filterung) oder durch völlig unterschiedliche Datensätze für jede Ebene erfolgen.
MichaelHouse
3
Mit einem Wort, es ist Gruppierung. Gruppieren Sie gute Kugeln und prüfen Sie nur, ob sie gegen böse Jungs kollidieren. Flixel hat ein solches Konzept.
Asche999
3
Ein pingeliger Design-Hinweis: Möchten Sie, dass 'Friendly-Fire'-Schüsse treffen, aber keinen Schaden anrichten, oder möchten Sie, dass sie Verbündete vollständig ignorieren und möglicherweise durch sie hindurchgehen, um stattdessen Feinde zu schlagen?
Steven Stadnicki

Antworten:

6

Kollisionsfilterung

Eine robustere Situation, die sich in viele Ebenen skalieren lässt, ist die Verwendung der Filterung, die nicht mit der Gruppierung identisch ist.

Dies funktioniert am besten, indem Sie jedem Objekt 2 Bitmasken geben .

Category
Mask

Und nur dann eine Kollision auslösen, wenn das Folgende zutrifft.

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

Es ist am einfachsten, die Maske auf 0xFFFF zu setzen, was dazu führt, dass sie mit allem kollidiert. Standardmäßig ist die Kategorie 0x0001. Objekte kollidieren mit den Kategorien in der anderen Maske. Es kommt zu einer Kollision.

Eine andere Möglichkeit ist, dass jedes Objekt einen Typ und eine Liste aller Typen hat, mit denen es kollidieren kann. Nur wenn zwei Objekte miteinander kollidieren, kommt es zu einer Kollision. Sie könnten das gleiche Verhalten haben, wenn Sie eine Liste von Aufzählungen anstelle einer Maske haben, aber eine Maske in einer Größenordnung schneller.

Szenario, das Sie beschreiben

In dieser Situation nutze ich gerne Aufzählungen.

Also sagen wir haben.

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

Kugel von einem guten Kerl erschossen

 Category = Bullet
 Mask = BadGuy | GlassWall

Gute Jungs

 Category = GoodGuy
 Mask = All

Böse Jungs

 Category = BadGuy
 Mask = All

Was zu dem Ergebnis führt, wenn eine von einem guten Kerl abgefeuerte Kugel einen anderen guten Kerl trifft.

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

Aber es wird böse Jungs treffen.

(All & BadGuy) != 0 && <- Passes
(BadGuy & (BadGuy | GlassWall)) != 0; <-- Passes
ClassicThunder
quelle
Würde es Ihnen etwas ausmachen, dies konzeptionell zu erklären, anstatt es auf einer kleinen Ebene der Bitarithmetik zu erklären?
Daniel Kaplan
@tieTYT sicher noch einmal in 5 Minuten überprüfen
ClassicThunder
2

Ich hatte das gleiche Problem bei meinem aktuellen Projekt (in Java). Nach ein paar Versuchen wird es durch Erstellen von vier Listen gelöst. Diese Lösung wurde in Java und für ein 2D-Spiel erstellt, sollte aber in ähnlicher Weise auch in JavaScript funktionieren

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
       {...}
}

Pseudocode

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

Pseudocode, gleich für die Klasse Bullets

Dies ist möglicherweise nicht die beste oder schnellste Lösung, hilft Ihnen jedoch im Moment. Es tut mir leid, dass ich Ihnen keine Lösung in JavaScript geben kann, aber ich hoffe, ich konnte Ihnen helfen

Mein Englisch ist übrigens nicht das beste, aber ich hoffe, Sie konnten meiner Erklärung folgen

Jonniy
quelle