Implementierung von quadratischen Tilemaps: Scrollende Karten
Dieser Artikel behandelt die Implementierung von scrollenden quadratischen Tilemaps mithilfe der Canvas API.
Hinweis: Beim Schreiben dieses Artikels haben wir angenommen, dass die Leser Vorkenntnisse über die Grundlagen des Canvas haben, wie z.B. das Erhalten eines 2D-Canvas-Kontexts, das Laden von Bildern usw., was alles im Canvas API Tutorial erklärt wird. Darüber hinaus basiert dieser Artikel auf den grundlegenden Informationen, die in unserem Einführungsartikel Tilemaps enthalten sind. Dieser Artikel baut auch auf der Implementierung statischer quadratischer Tilemaps auf — Sie sollten diesen ebenfalls lesen, falls Sie dies noch nicht getan haben.
Die Kamera
Die Kamera ist ein Objekt, das Informationen darüber enthält, welcher Abschnitt der Spielwelt oder des Levels gerade angezeigt wird. Kameras können entweder frei beweglich sein und vom Spieler gesteuert werden (wie in Strategie-Spielen) oder einem Objekt folgen (wie dem Hauptcharakter in Plattformspielen).
Unabhängig vom Kameratyp benötigen wir immer Informationen über die aktuelle Position, die Größe des Ansichtsfensters usw. In der bereitgestellten Demo zusammen mit diesem Artikel sind dies die Parameter, die die Kamera hat:
x
undy
: Die aktuelle Position der Kamera. In dieser Implementierung gehen wir davon aus, dass(x,y)
auf die obere linke Ecke des sichtbaren Teils der Karte zeigt.width
undheight
: Die Größe des Ansichtsfensters der Kamera.maxX
undmaxY
: Die Grenze für die Position der Kamera — Die untere Grenze wird fast immer(0,0)
sein, und in diesem Fall ist die obere Grenze gleich der Größe der Welt minus der Größe des Ansichtsfensters der Kamera.
Rendering der Karte
Es gibt zwei wesentliche Unterschiede zwischen dem Rendering von scrollenden Karten und statischen Karten:
-
Teilweise Kacheln können angezeigt werden. In statischen Karten beginnt das Rendering normalerweise in der oberen linken Ecke einer Kachel, die sich in der oberen linken Ecke eines Ansichtsfensters befindet. Während des Renderings von scrollenden Tilemaps wird oft die erste Kachel abgeschnitten.
-
Nur ein Abschnitt der Karte wird gerendert. Wenn die Karte größer ist als das Ansichtsfenster, können wir offensichtlich nur einen Teil davon gleichzeitig anzeigen, während nicht-scrollende Karten normalerweise vollständig gerendert werden.
Um diese Probleme zu bewältigen, müssen wir den Rendering-Algorithmus leicht anpassen. Stellen Sie sich vor, die Kamera zeigt auf (5,10)
. Das bedeutet, dass die erste Kachel 0x0
wäre. Im Democode wird der Startpunkt in startCol
und startRow
gespeichert. Es ist auch praktisch, die letzte zu rendernde Kachel vorab zu berechnen.
const startCol = Math.floor(this.camera.x / map.tsize);
const endCol = startCol + this.camera.width / map.tsize;
const startRow = Math.floor(this.camera.y / map.tsize);
const endRow = startRow + this.camera.height / map.tsize;
Sobald wir die erste Kachel haben, müssen wir berechnen, wie viel deren Rendering (und somit das Rendering der anderen Kacheln) verschoben wird. Da die Kamera auf (5, 10)
zeigt, wissen wir, dass die erste Kachel um (-5,-10)
Pixel verschoben werden sollte. In unserer Demo wird der Verschiebungsbetrag in den Variablen offsetX
und offsetY
gespeichert.
const offsetX = -this.camera.x + startCol * map.tsize;
const offsetY = -this.camera.y + startRow * map.tsize;
Mit diesen Werten an Ort und Stelle ist die Schleife, die die Karte rendert, derjenigen, die für das Rendering statischer Tilemaps verwendet wird, ziemlich ähnlich. Der Hauptunterschied besteht darin, dass wir die Werte offsetX
und offsetY
zu den Zielkoordinaten x
und y
hinzufügen, und diese Werte werden gerundet, um Artefakte zu vermeiden, die entstehen würden, wenn die Kamera auf Positionen mit Gleitkommazahlen zeigt.
for (let c = startCol; c <= endCol; c++) {
for (let r = startRow; r <= endRow; r++) {
const tile = map.getTile(c, r);
const x = (c - startCol) * map.tsize + offsetX;
const y = (r - startRow) * map.tsize + offsetY;
if (tile !== 0) {
// 0 => empty tile
this.ctx.drawImage(
this.tileAtlas, // image
(tile - 1) * map.tsize, // source x
0, // source y
map.tsize, // source width
map.tsize, // source height
Math.round(x), // target x
Math.round(y), // target y
map.tsize, // target width
map.tsize, // target height
);
}
}
}
Demo
Unsere Demo zur Implementierung von scrollenden Tilemaps führt den obigen Code zusammen, um zu zeigen, wie eine Implementierung dieser Karte aussieht. Sie können sich eine Live-Demo ansehen und den Quellcode dazu betrachten.
Es gibt eine weitere Demo, die zeigt, wie man die Kamera einem Charakter folgen lässt.