2016-04-08 14 views
1

ich mich gefragt, ob jemand könnte mir helfen Figur, wie Kollisionen in einem 2D-Array zwischen zwei Objekten zu überprüfen.XNA Fliese basierte Spiel: Überprüfung auf Kollision zwischen zwei Objekten ihrer Startposition in einem Array 2D mit

Ich versuche, ein einfaches 2D-Top-Down-Spiel zu machen. Die Karte besteht aus einem 20x20 2D Array von Quadraten. Der Spieler und die Feinde sind alle Quadrate und nehmen jeweils ein Feld innerhalb des Gitters ein. Das Gitter besteht aus mehreren Quadraten unterschiedlicher Typen. Bisher habe ich Floor Squares (auf denen sich Spieler und Gegner bewegen dürfen), Wallquadrate (an denen der Spieler und die Feinde nicht vorbei- oder mitgehen können) und dann den Gegner und die Spielerquadrate. Hier ist ein Screenshot davon:

enter image description here

ich erstellen und initialisieren den 2D-Array in der Spielklasse. Mit Zahlen von 0 bis 3 kann ich wählen, was jedes Quadrat enthält: 0- Boden Quadrat 1- Wand Quadrat 2- Feind Quadrat 3- Spieler Quadrat.

Zuerst muss der Spieler mit den Wandquadraten kollidieren, indem er einfach eine verschachtelte for-Schleife verwendet und die Gitterpositionen Oben, Unten, Links und Rechts des Spielers überprüft, ob der Wert innerhalb des 2D-Arrays 1 ist. Wenn dies nicht der Fall ist, bedeutet das, dass es keine Wand ist, die bedeutet, dass der Spieler sich bewegen darf.

Allerdings kann ich diese Methode nicht verwenden, wenn ich die Kollision zwischen Spieler und Gegner überprüfe, da ich nur den Wert innerhalb des 2D-Arrays (2 und 3) verwende, um zu wählen, wo der Gegner und die Spielerquadrate ursprünglich gezogen werden sollen. Das bedeutet, dass die Gitterposition, auf der sie sich gerade befinden, zu jeder Zeit einen Wert von 0 enthält.

Ich dachte, ich würde darüber nachdenken, indem ich die "Gitterposition" jedes Spielers und jedes gegnerischen Objekts speichere. Auf diese Weise konnte ich einfach jeden Gitterblock um den Spieler überprüfen, um zu sehen, ob er der Gitterposition eines Gegners entsprach. Wenn es gleich wäre, würde ich den Bewegungsvektor einstellen, den ich verwende, um den Spieler in diese spezifische Richtung zu bewegen (0,0), wodurch verhindert wird, dass er sich in diese Richtung bewegt. Wenn sich der Gegner nicht mehr innerhalb eines Blocks des Spielers befindet, wird der Bewegungsvektor wieder zurückgegeben.

Ich hatte Erfolg damit, aber es scheint nur mit einem Feindobjekt zu arbeiten. Mit einem Feind kann ich ihn nicht aus irgendeinem Winkel passieren, aber mit den anderen kann ich durch sie hindurchgehen.

Hinweis: Es scheint, dass der Feind am weitesten unten über das Display der einzige Feind ist, dass der Spieler Platz mit kollidieren kann.

Ich habe Breakpoints benutzt und ich kann sehen, dass wenn ich nahe an einen der Gegner herankomme, der durchgeht, es den Check ausführt, um zu sehen, ob das Quadrat neben dem Spieler ein Feind ist, aber nicht Der Spieler kann nicht verhindern, dass der Spieler durch den Feind läuft.

Also meine Frage ist, werde ich über die Kollision falsch zu machen, gibt es einen einfacheren Weg, es zu tun? Oder ob es vielleicht einen Fehler in meinem Code gibt, der ihn daran hindert zu arbeiten?

Im Folgenden finden Sie einige meinen Code:

Diese erste Probe ist für den Spieler/Feind Kollision. Dies ist in der feindlichen Klasse enthalten. Wie ich bereits erwähnt habe, benutze ich die Gitterposition des Spielers und des Feindes, um zu sehen, ob sie innerhalb eines Quadrates liegen. Wenn sie das sind, setze ich den Bewegungsvektor des Spielers auf 0,0. Wenn sie sich nicht mehr innerhalb eines Quadrates befinden, setze ich den Bewegungsvektor auf seinen ursprünglichen Wert zurück.

Der nächste Teil des Codes ist für, wo ich die Werte innerhalb der 2D-Array festlegen und das Layout des Levels erstellen. Dort erstelle ich auch die feindlichen Objekte und setze die Position und die Position des Spielers und die Position des Spielers unter Verwendung der Reihe, Spalte ihrer spezifischen "Zahl" auf dem Gitter, um zu wählen, wo sie gezeichnet werden sollen.

Hinweis: Die Zeilen und Spalten werden umgedreht, da sonst die Ebene zur Seite gezogen wird.

public void LoadLevels(int level) 
    { 
     //More levels will be added in later. 
     if(level == 1) 
     { 
      //Here I set the values inside the 2D array "grid". It is a 20x20 array. 
      //0 = Floor Square, 1 = Wall square, 2 = Enemy Square, 3 = Player Square 
      grid = new int[maxRows, maxCols] 
      { 
       {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 
       {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 
       {1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1}, 
       {1,0,1,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0,0,1}, 
       {1,0,1,0,1,1,0,1,0,1,1,0,1,1,1,1,1,1,0,1}, 
       {1,0,1,2,1,1,0,1,0,1,1,0,0,0,0,0,0,0,0,1}, 
       {1,0,1,0,1,1,0,1,0,0,0,0,1,1,1,0,1,1,1,1}, 
       {1,0,1,0,1,1,0,1,0,1,1,0,0,0,0,0,0,0,0,1}, 
       {1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,1,1}, 
       {1,1,1,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1}, 
       {1,0,0,0,0,0,0,0,0,1,1,1,0,1,1,1,1,1,0,1}, 
       {1,1,1,1,1,1,1,1,0,0,0,3,0,0,0,2,0,0,0,1}, 
       {1,0,1,0,0,0,0,1,0,1,0,1,0,1,0,1,1,1,0,1}, 
       {1,2,1,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1}, 
       {1,0,1,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1}, 
       {1,0,1,2,1,1,0,1,0,1,0,1,0,1,0,0,0,0,0,1}, 
       {1,0,1,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1}, 
       {1,0,1,0,1,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1}, 
       {1,0,0,0,0,0,0,0,0,1,0,1,0,1,0,1,1,1,0,1}, 
       {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1} 
      }; 
      //Cycle through the array with a nested if 
      for (int i = 0; i < maxCols; i++) 
      { 
       for (int j = 0; j < maxRows; j++) 
       { 
        //If the the value at grid[i, j] is a 2 then create an enemy at that position 
        if (grid[i, j] == 2) 
        { 
         enemyList.Add(new Enemies(Content.Load<Texture2D>("redSquare"), new Vector2(j * squareWidth, i * squareHeight), new Vector2(j, i))); 
         //Reset the value at this position to 0 so that when the player/enemy moves from this spot, a floor tile will be drawn instead of a blank space. 
         grid[i, j] = 0; 
        } 
        //If the value is 3 then set the players position and grid position to the value based of [i, j] values. 
        if (grid[i, j] == 3) 
        { 
         playerObject.PlayerPosition = new Vector2(i * squareWidth, j * squareHeight); 
         playerObject.PlayerGridPosition = new Vector2(i, j); 
         grid[i, j] = 0; 
        } 
       } 
      } 

     } 
     if (level == 2) 
     { 
     } 
    } 

Antwort

2

Jedoch kann ich diese Methode nicht verwenden, wenn eine Kollision zwischen dem Spieler und Gegner überprüft, wie ich nur den Wert innerhalb des Arrays 2D verwenden (2 und 3) zu wählen, wo die ursprünglich an den Feind und Spieler Quadrate zeichnen .

Vielleicht ist dies ein Fehler in Ihrem Design, den Sie beheben sollten, anstatt zu arbeiten. Ich habe nicht genug Code, um genau zu sagen, aber es scheint, als würden Sie Informationen innerhalb der Player-Klasse oder vielleicht eines anderen Gitters duplizieren. Basierend auf Ihrer Beschreibung beschreibt ein 2D-Gitter mit den Werten 0-1-2-3 für jedes Quadrat den Zustand des Spiels. Warum nicht einfach das Gitter als single source of truth für alles verwenden?

1

Randbemerkung: Sie scheinen für Westen fehlenden Code werden. Wenn das unbeabsichtigt ist, sollte es eine einfache Lösung sein.

Ich denke, was passieren kann, ist, sobald ein Feind nicht neben dem Spieler ist, erlaubt es dem Spieler, in alle Richtungen wieder zu gehen, unabhängig von den Einschränkungen früherer Monster.

Wenn ich richtig bin, was passiert, überprüft es jeden Gegner in absteigender Bildschirmposition und blockiert den Spieler, wenn er dann benötigt wird. Wenn sich jedoch einer der verbleibenden Gegner nicht neben dem Spieler befindet, wird die Änderung rückgängig gemacht, wenn die Prüfung für diesen Gegner durchgeführt wird und der Spieler erneut hindurchlaufen darf. Dies geschieht nicht für den letzten Feind, weil sie nicht mehr nicht benachbarte Feinde sind, um ihre Blockierung rückgängig zu machen.

Versuchen Sie es so zu ändern, dass es die erlaubten Bewegungen am Anfang jedes Frames zurücksetzt, im Gegensatz zu jedem Mal, wenn es ein Monster nicht neben dem Spieler findet.

2

Es ist schwer zu finden, wo der eigentliche Bug, ohne den vollständigen Code & zu sehen Debuggen Sie es direkt, aber ich fühle, dass Ihr Ansatz zu kompliziert ist.

Persönlich werde ich die folgende Logik/Pseudo-Code folgen:

loading() { 
    load level to array, no need to perform additional modification 
} 
game_update() { 
    for each tile within the array { 
     if (tile is player) { 
      read user's input 
      temp <- compute the next position of the player 
      if (temp is floor) then { current player position <- temp } // move allowed, update its position 
      else { the player must stay on its current position } // move rejected 
     } 
     if (tile is enemy) { 
      temp <- compute the next position of this enemy 
      if (temp is floor) then { this enemy position <- temp } // move allowed, update its position 
      else { this enemy must stay on its current position } // move rejected 
     } 
    } 
} 
game_draw() { 
    for each tile within the array { 
     draw the current tile 
    } 
} 

Auf diese Weise wird jede ilegal Bewegung blockiert werden, bevor es auftritt.