Wie fängt man ein Projekt wie dieses an? Ich persönlich möchte immer möglichst schnell etwas sehen, also fange ich damit an, die Objekte zu zeichnen, die das Spiel ausmachen. Diese sind: Wände, Kisten, Ziele und die Spielfigur. Das Spiel ist vorbei, wenn sich auf jedem Ziel eine Kiste befindet.
Das Canvas
Als Zeichenfläche verwende ich das HTML-Element canvas. Dazu lege ich zunächst eine einfache Datei namens sokoban.html an:
<canvas id="canvas"></canvas>
<script type="text/javascript" src="sokoban.js"></script>
Das reicht für den Anfang. Die Dimensionen des canvas werden im Javascript festgelegt.
Das erste Level
Um etwas zu haben, das ich zeichnen kann, definiere ich in der Datei sokoban.js mein erstes Level:
const level = {
size: {
width: 10,
height: 10
},
walls: [
{ x: 0, y: 0},
{ x: 0, y: 1},
{ x: 0, y: 2},
{ x: 0, y: 3},
{ x: 0, y: 4},
{ x: 0, y: 5},
{ x: 0, y: 6},
{ x: 0, y: 7},
{ x: 0, y: 8},
{ x: 0, y: 9},
{ x: 1, y: 0},
{ x: 2, y: 0},
{ x: 3, y: 0},
{ x: 4, y: 0},
{ x: 5, y: 0},
{ x: 6, y: 0},
{ x: 7, y: 0},
{ x: 8, y: 0},
{ x: 9, y: 0},
{ x: 9, y: 1},
{ x: 9, y: 2},
{ x: 9, y: 3},
{ x: 9, y: 4},
{ x: 9, y: 5},
{ x: 9, y: 6},
{ x: 9, y: 7},
{ x: 9, y: 8},
{ x: 9, y: 9},
{ x: 1, y: 9},
{ x: 2, y: 9},
{ x: 3, y: 9},
{ x: 4, y: 9},
{ x: 5, y: 9},
{ x: 6, y: 9},
{ x: 7, y: 9},
{ x: 8, y: 9},
]
};
Dieses erste Level enthält zunächst nur Wände, und zwar ein einem Rahmen der Größe 10×10. Diese Größe wird oben in meinem Level-Objekt definiert. Jede einzelne Wand ist ein Quadrat, das eine x- und eine y-Koordinate in meinem Level hat. Als nächstes will ich diese Wände auf mein canvas zeichnen:
const pixelPerBlock = 20;
const canvas = document.getElementById("canvas");
canvas.width = level.size.width * pixelPerBlock;
canvas.height = level.size.height * pixelPerBlock;
const ctx = canvas.getContext("2d");
for (const wall of level.walls) {
let wallPixel = coordinatesToPixel(wall);
ctx.fillStyle = "#555"
ctx.fillRect(wallPixel.x, wallPixel.y, pixelPerBlock, pixelPerBlock);
}
function coordinatesToPixel({x, y}) {
return { x: x*pixelPerBlock, y: y*pixelPerBlock };
}
Jedes Spiel-Objekt, einschließlich der Wände, hat die selbe Größe. Ich lege diese zunächst auf 20 Pixel pro Block fest. Anschließend finde ich das canvas im DOM und setze seine Größe gemäß den Dimensionen des Levels. Dann hole ich mir einen 2d-Kontext vom canvas. Dieses Objekt erlaubt es mir, eine zweidimensionale Zeichnung anzufertigen.
Die Funktion coordinatesToPixel rechnet die abstrakten Koordinaten meines Level-Objektes in konkrete Pixel-Koordinaten um. Das mache ich für jede Wand und dann zeichne ich ein graues Quadrat an die entsprechende Stelle. Das Ergebnis sieht folgendermaßen aus:

Fazit und Ausblick
Ein erster Erfolg! Mir ist es gelungen, die Wände eines Sokoban-Levels auf ein canvas-Element zu zeichnen. Als nächstes werde ich die Spielfigur zeichnen und dafür sorgen, dass man sie mit den Pfeiltasten steuern kann.
