Kollisionsdetektion
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 einsehen.
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 Hinzufügung einer Kollisionsdetektion nachdenken, damit er von den Steinen abprallen und sie zerbrechen kann.
Es liegt natürlich an uns, wie wir das umsetzen wollen, aber es kann schwierig sein, zu berechnen, ob der Ball das Rechteck berührt, da es dafür keine Hilfsfunktionen in Canvas gibt. Für den Zweck dieses Tutorials werden wir es auf die einfachste mögliche Weise tun. Wir werden prüfen, ob das Zentrum des Balls mit einem der gegebenen Steine kollidiert. Das wird nicht jedes Mal ein perfektes Ergebnis liefern, und es gibt viel ausgeklügeltere Methoden zur Kollisionsdetektion, aber das wird ausreichen, um Ihnen die grundlegenden Konzepte zu vermitteln.
Eine Kollisionsdetektionsfunktion
Um dies alles zu starten, wollen wir eine Kollisionsdetektionsfunktion erstellen, die alle Steine durchläuft und die Position jedes einzelnen Steins mit den Koordinaten des Balls vergleicht, während jedes Frame gezeichnet wird. Für eine bessere Lesbarkeit des Codes definieren wir die Variable b
, um das Steinobjekt in jeder Schleife der Kollisionsdetektion zu speichern:
function collisionDetection() {
for (let c = 0; c < brickColumnCount; c++) {
for (let r = 0; r < brickRowCount; r++) {
const b = bricks[c][r];
// calculations
}
}
}
Wenn das Zentrum des Balls innerhalb der Koordinaten eines unserer Steine liegt, ändern wir die Richtung des Balls. Damit das Zentrum des Balls innerhalb des Steins liegt, müssen alle vier der folgenden Aussagen wahr sein:
- 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 im Code festhalten:
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 zu Ihrem Code hinzu, unterhalb der Funktion keyUpHandler()
.
Verschwinden der Steine nach einem Treffer
Der obige Code funktioniert wie gewünscht und der Ball ändert seine Richtung. Das Problem ist, dass die Steine dort bleiben, wo sie sind. Wir müssen herausfinden, wie wir diejenigen loswerden, die wir bereits mit dem Ball getroffen haben. Wir können das tun, indem wir einen zusätzlichen Parameter hinzufügen, um anzugeben, ob wir jeden Stein auf dem Bildschirm malen wollen 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 in der hervorgehobenen Zeile angegeben:
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 der status
-Eigenschaft jedes Steins in der Funktion drawBricks()
vor dem Zeichnen — wenn status
1
ist, dann zeichnen Sie ihn, aber wenn es 0
ist, dann wurde er vom Ball getroffen und soll nicht mehr auf dem Bildschirm erscheinen. Aktualisieren Sie Ihre drawBricks()
Funktion wie folgt:
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 Kollisionsdetektionsfunktion
Jetzt müssen wir die status
-Eigenschaft der Steine in die Funktion collisionDetection()
einbeziehen: Wenn der Stein aktiv ist (sein Status ist 1
), prüfen wir, ob eine Kollision stattfindet; wenn eine Kollision auftritt, setzen wir den Status des gegebenen Steins auf 0
, sodass er nicht mehr auf dem Bildschirm gezeichnet wird. Aktualisieren Sie Ihre collisionDetection()
Funktion wie unten angegeben:
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 Kollisionsdetektion
Das letzte, was zu tun ist, ist einen Aufruf der Funktion collisionDetection()
zu unserer Hauptfunktion draw()
hinzuzufügen. Fügen Sie die folgende Zeile in die draw()
Funktion ein, direkt unter dem Aufruf von drawPaddle()
:
collisionDetection();
Vergleichen Sie Ihren Code
Die Kollisionsdetektion des Balls wird jetzt in jedem Frame und mit jedem Stein überprüft. Jetzt können wir Steine zerstören! :-)
Nächste Schritte
Wir nähern uns definitiv unserem Ziel; lassen Sie uns weitermachen! Im achten Kapitel werden wir uns damit beschäftigen, wie man den Punktestand verfolgt und gewinnt.