Dieser Inhalt wurde automatisch aus dem Englischen übersetzt, und kann Fehler enthalten. Erfahre mehr über dieses Experiment.

View in English Always switch to English

Kollisionserkennung

Dies ist der 7. Schritt von 10 des Gamedev Canvas Tutorials. Sie können den Quellcode, wie er nach Abschluss dieser Lektion aussehen sollte, unter Gamedev-Canvas-workshop/lesson7.html finden.

Die Steine erscheinen bereits auf dem Bildschirm, aber das Spiel ist noch nicht so interessant, da der Ball durch sie hindurchgeht. Wir müssen über die Implementierung einer Kollisionserkennung nachdenken, sodass der Ball von den Steinen abprallt und sie zerbricht.

Es liegt natürlich in unserer Entscheidung, wie wir dies umsetzen, aber es kann schwierig sein, zu berechnen, ob der Ball das Rechteck berührt oder nicht, da es dafür keine Hilfsfunktionen in Canvas gibt. Für den Zweck dieses Tutorials werden wir es auf die einfachste Weise tun. Wir werden prüfen, ob das Zentrum des Balls mit einem der gegebenen Steine kollidiert. Dies wird nicht immer ein perfektes Ergebnis liefern, und es gibt viel ausgeklügeltere Methoden zur Kollisionserkennung, aber es wird ausreichen, um Ihnen die grundlegenden Konzepte beizubringen.

Eine Kollisionserkennungsfunktion

Um dies alles einzuleiten, wollen wir eine Kollisionserkennungsfunktion erstellen, die alle Steine durchläuft und die Position jedes einzelnen Steins mit den Koordinaten des Balls vergleicht, während jedes Bild gezeichnet wird. Zur besseren Lesbarkeit des Codes werden wir die Variable b definieren, um das Steinobjekt in jeder Schleife der Kollisionserkennung zu speichern:

js
function collisionDetection() {
  for (let c = 0; c < brickColumnCount; c++) {
    for (let r = 0; r < brickRowCount; r++) {
      const b = bricks[c][r];
      // calculations
    }
  }
}

Wenn sich das Zentrum des Balls innerhalb der Koordinaten eines unserer Steine befindet, ändern wir die Richtung des Balls. Damit sich das Zentrum des Balls innerhalb eines Steins befindet, müssen alle vier der folgenden Aussagen zutreffen:

  • Die x-Position des Balls ist größer als die x-Position des Steins.
  • Die x-Position des Balls ist kleiner als die x-Position des Steins plus seiner Breite.
  • Die y-Position des Balls ist größer als die y-Position des Steins.
  • Die y-Position des Balls ist kleiner als die y-Position des Steins plus seiner Höhe.

Lassen Sie uns das in Code festhalten:

js
function collisionDetection() {
  for (let c = 0; c < brickColumnCount; c++) {
    for (let r = 0; r < brickRowCount; r++) {
      const b = bricks[c][r];
      if (x > b.x && x < b.x + brickWidth && y > b.y && y < b.y + brickHeight) {
        dy = -dy;
      }
    }
  }
}

Fügen Sie den obigen Block unter der keyUpHandler()-Funktion in Ihren Code ein.

Die Steine verschwinden lassen, nachdem sie getroffen wurden

Der obige Code wird wie gewünscht funktionieren und der Ball ändert seine Richtung. Das Problem ist, dass die Steine bleiben, wo sie sind. Wir müssen einen Weg finden, die bereits mit dem Ball getroffenen Steine loszuwerden. Wir können dies tun, indem wir einen zusätzlichen Parameter hinzufügen, um anzuzeigen, ob wir jeden Stein auf dem Bildschirm malen möchten oder nicht. In dem Teil des Codes, in dem wir die Steine initialisieren, fügen wir jedem Steinobjekt eine status-Eigenschaft hinzu. Aktualisieren Sie den folgenden Teil des Codes, wie durch die hervorgehobene Zeile angezeigt:

js
let bricks = [];

for (let c = 0; c < brickColumnCount; c++) {
  bricks[c] = [];
  for (let r = 0; r < brickRowCount; r++) {
    bricks[c][r] = { x: 0, y: 0, status: 1 };
  }
}

Als Nächstes überprüfen wir den Wert jeder status-Eigenschaft der Steine in der drawBricks()-Funktion, bevor wir sie zeichnen — wenn status auf 1 gesetzt ist, dann zeichnen wir ihn, aber wenn er 0 ist, dann wurde er vom Ball getroffen und wir wollen ihn nicht mehr auf dem Bildschirm haben. Aktualisieren Sie Ihre drawBricks()-Funktion wie folgt:

js
function drawBricks() {
  for (let c = 0; c < brickColumnCount; c++) {
    for (let r = 0; r < brickRowCount; r++) {
      if (bricks[c][r].status === 1) {
        const brickX = c * (brickWidth + brickPadding) + brickOffsetLeft;
        const brickY = r * (brickHeight + brickPadding) + brickOffsetTop;
        bricks[c][r].x = brickX;
        bricks[c][r].y = brickY;
        ctx.beginPath();
        ctx.rect(brickX, brickY, brickWidth, brickHeight);
        ctx.fillStyle = "#0095DD";
        ctx.fill();
        ctx.closePath();
      }
    }
  }
}

Verfolgen und Aktualisieren des Status in der Kollisionserkennungsfunktion

Jetzt müssen wir die status-Eigenschaft des Steins in die collisionDetection()-Funktion einbeziehen: Wenn der Stein aktiv ist (sein Status ist 1), werden wir prüfen, ob die Kollision auftritt; falls eine Kollision auftritt, setzen wir den Status des gegebenen Steins auf 0, sodass er nicht mehr auf dem Bildschirm angezeigt wird. Aktualisieren Sie Ihre collisionDetection()-Funktion wie unten angegeben:

js
function collisionDetection() {
  for (let c = 0; c < brickColumnCount; c++) {
    for (let r = 0; r < brickRowCount; r++) {
      const b = bricks[c][r];
      if (b.status === 1) {
        if (
          x > b.x &&
          x < b.x + brickWidth &&
          y > b.y &&
          y < b.y + brickHeight
        ) {
          dy = -dy;
          b.status = 0;
        }
      }
    }
  }
}

Aktivierung unserer Kollisionserkennung

Der letzte Schritt besteht darin, einen Aufruf an die collisionDetection()-Funktion in unsere Haupt-draw()-Funktion einzufügen. Fügen Sie die folgende Zeile in die draw()-Funktion ein, direkt unterhalb des drawPaddle()-Aufrufs:

js
collisionDetection();

Vergleichen Sie Ihren Code

Die Kollisionserkennung des Balls wird jetzt in jedem Frame mit jedem Stein überprüft. Jetzt können wir Steine zerstören! :-)

Nächste Schritte

Wir nähern uns dem Ende; machen wir weiter! Im achten Kapitel werden wir uns ansehen, wie Sie den Punktestand verfolgen und gewinnen können.