Anhand vom Snake game sollen Sie verstehen, wofür JavaScript beispielsweise verwendet werden kann und dies auch etwas „ausprobieren“.
JavaScript ist eine Programmiersprache, die ursprünglich für die Entwicklung interaktiver Webseiten genutzt wurde.
Die json Programme werden direkt im Browser ausgeführt und ermöglichen, Webseiten dynamisch zu gestalten und auf Benutzeraktionen zu reagieren.
Heute wird JavaScript aber weit über den Browser hinaus eingesetzt und eine wichtige Programmiersprache für Webentwicklung, Server-Anwendungen, mobile Apps und sogar Desktop-Software geworden. Die Sprache ist dynamisch typisiert (Typ einer Variable wird erst zur Laufzeit bestimmt), relativ einfach zu erlernen und sehr vielseitig einsetzbar.
Das Ziel des Spiels ist es, die Schlange (das kleine Quadrat) zu steuern und das Futter zu fressen. Dadurch wird die Schlange länger und Punkte werden gesammelt. Aber Achtung: Das Spiel endet, wenn die Schlange gegen die Wand stößt oder sich selbst berührt!
des folgenden Ordners herunter: Link auf Onedrive von CMarro. Darin befindet sich eine app.css, eine app.js, eine html-Datei darin, die Sie nutzen müssen.
Sie finden in diesem Ordner neben einer css-Datei (app.css) auch eine htm-Datei (index.html).
Auftrag 1
Dabei Kann die Extension „Live Preview“ helfen, um das html immer direkt anzuschauen. Natürlich kann auch die html-Datei via Browser geöffnet werden und dann jeweils durch ein Refresh beobachtet werden,was passiert.
Studieren Sie das Programm, Ziel ist ein grobes Verständnis des Programms.
Hier werden die Variablen festgelegt. Es gibt hier Listen, Objekte oder einfache Wertvariablen. Alle sind leer oder auf 0 gesetzt.
'use strict'; var gameStart = {}, gameSpeed = {}, gameArea = {}, manualStep = {}, gameAreaContext = {}, snake = [], gameAreaWidth = 0, gameAreaHeight = 0, cellWidth = 0, playerScore = 0, snakeFood = {}, snakeDirection = '', speedSize = 0, timer = {};
Dies ist eine Funkion, welche die Startgeschwindigkeit oder auch den Startzeitpunkt etc initialisieren, darin enthalten ist auch das Spielfeld 400×600
function initElement() { gameStart = document.querySelector('#gameStart'); gameSpeed = document.querySelector('#gameSpeed'); gameArea = document.querySelector('#gameArea'); manualStep = document.querySelector('#manualStep'); gameAreaContext = gameArea.getContext('2d'); gameAreaWidth = 400; gameAreaHeight = 600; cellWidth = 20; gameArea.width = gameAreaWidth; gameArea.height = gameAreaHeight; }
Das Spielfeld wird erstellt mit dieser Funktion, wenn Sie dann aufgerufen wird. Spielfeldhiintergrund ist weiss (FFFFF).
function createGameArea() { gameAreaContext.fillStyle = '#FFFFFF'; gameAreaContext.fillRect(0, 0, gameAreaWidth, gameAreaHeight); gameAreaContext.strokeStyle = '#000000'; gameAreaContext.strokeRect(0, 0, gameAreaWidth, gameAreaHeight); }
Hier wird das 'Essen' der Schlange erstellt, sobald dies aufgerufen wird, dabei wird es zufällig auf dem Spielfeld platziert.
function createFood() { snakeFood = { x: Math.round(Math.random() * (gameAreaWidth - cellWidth) / cellWidth), y: Math.round(Math.random() * (gameAreaHeight - cellWidth) / cellWidth), }; }
Hier wird überprüft, ob die Schlange sich selber trifft, was ja nicht sein darf, sonst ist das Spiel vorbei.
function snakeOnItself(x, y, array) { for (var index = 0, length = array.length; index < length; index++) { if (array[index].x == x && array[index].y == y) return true; } return false; }
Hier wird der Score geschrieben, sobald fertig gespielt wurde.
function writeScore() { gameAreaContext.font = '50px sans-serif'; gameAreaContext.fillStyle = '#FF0000'; gameAreaContext.fillText('Score: ' + playerScore, (gameAreaWidth / 2) - 100, gameAreaHeight / 2); }
Hier wird ein Quadrat für die Spielfläche generiert
function createSquare(x, y) { gameAreaContext.fillStyle = '#000000'; gameAreaContext.fillRect(x * cellWidth, y * cellWidth, cellWidth, cellWidth); }
Der folgnede Code ist die Steuerung der Schlange.
function checkDirectionUpdatePosition() { var snakeX = snake[0].x; var snakeY = snake[0].y; if (snakeDirection == 'right') { snakeX++; } else if (snakeDirection == 'left') { snakeX--; } else if (snakeDirection == 'down') { snakeY++; } else if (snakeDirection == 'up') { snakeY--; } return { snakeX, snakeY }; }
Hier wird überprüft, ob die Schlange das 'Essen' erwischt hat oder nicht.
function didSnakeEatTheFood(snakeX, snakeY) { if (snakeX == snakeFood.x && snakeY == snakeFood.y) { return true; } else { return false; } }
Im Spiel ist immer wieder ein neues Update für das Spielfeld nötig.
function updateGameArea() { var snakeAteFootVar = false; var isSnakeOnItself = false createGameArea(); var newPosition = checkDirectionUpdatePosition(); var snakeX = newPosition.snakeX; var snakeY = newPosition.snakeY; }
Es wird mit dieser Funktiongeschaut, dass die Schlange auf dem Spielfeld bleibt.
function checkSnakeOutOfBounds(snakeX, snakeY) { if ((snakeX == -1) || (snakeX == gameAreaWidth / cellWidth) || (snakeY == -1) || (snakeY == gameAreaHeight / cellWidth)) { return true; } return false; }
Mit der folgenden Methode wird das Spiel gestartet.
function startGame() { // initally create snake snake = []; snake.push({ x: 0, y: cellWidth }); // create the food createFood(); // make the snake move automatically clearInterval(timer); timer = setInterval(updateGameArea, 500 / speedSize); } function stepOnClick() { updateGameArea(); } function onStartGame() { this.disabled = true; // reset score playerScore = 0; // reset direction to right snakeDirection = 'right'; // reset speed the set value speedSize = parseInt(gameSpeed.value); if (speedSize > 9) { speedSize = 9; } else if (speedSize < 0) { speedSize = 1; } startGame(); }
Mit den Tasten 37 bis 40 sind die Pfeiltasten nummeriert. Es wird auch geschaut, dass man nicht rückwärts wandern kann.
function changeDirection(e) { var keys = e.which; if (keys == '40' && snakeDirection != 'up') snakeDirection = 'down'; else if (keys == '39' && snakeDirection != 'left') snakeDirection = 'right'; else if (keys == '38' && snakeDirection != 'down') snakeDirection = 'up'; else if (keys == '37' && snakeDirection != 'right') snakeDirection = 'left'; }
Durch den Schitt für Schritt Button kann beim Programmieren viel ausprobiert werden.
function initEvent() { gameStart.addEventListener('click', onStartGame); manualStep.addEventListener('click', stepOnClick) window.addEventListener('keydown', changeDirection); } function init() { initElement(); createGameArea() initEvent(); } window.addEventListener('DOMContentLoaded', init);
Um etwas besser am Programm arbeiten zu können, hilft es eventuell, die folgenden Zeilen durch einen doppelten Backslash aus zu kommentieren:
// clearInterval(timer); //timer = setInterval(updateGameArea, 500 / speedSize);
Auftrag 2
Sie dürfen sich auch Hilfe bei einer KI einem LLM holen, falls Sie möchten.
Um die Farbe des Essens zu verändern, könnte die Funktion createSquare verdoppelt werden und dann bei der kopierten Version der Funktion kann die Farbe anders eingestellt werden, beispielsweise
gameAreaContext.fillStyle = '#FF0000'
und weiter unten dann
// create the food createSquare1(snakeFood.x, snakeFood.y);
Um ein Raster zu erhalten, muss die createGameArea() Funktion verändert werden, hier kann beispielsweise wie folgt vorgegangen werden:
function createGameArea() { gameAreaContext.fillStyle = '#FFFFFF'; gameAreaContext.fillRect(0, 0, gameAreaWidth, gameAreaHeight); gameAreaContext.strokeStyle = '#000000'; gameAreaContext.strokeRect(0, 0, gameAreaWidth, gameAreaHeight); // Raster zeichnen const gridSize = 20; // Größe der Rasterzellen gameAreaContext.strokeStyle = '#CCCCCC'; // Hellgraue Rasterlinien gameAreaContext.lineWidth = 1; // Vertikale Linien for (let ix = 0; ix <= gameAreaWidth; ix= gridSize+1) { gameAreaContext.beginPath(); gameAreaContext.moveTo(ix, 0); gameAreaContext.lineTo(ix, gameAreaHeight); gameAreaContext.stroke(); } // Horizontale Linien for (let iy = 0; iy <= gameAreaHeight; iy = gridSize+1) { gameAreaContext.beginPath(); gameAreaContext.moveTo(0, iy); gameAreaContext.lineTo(gameAreaWidth, iy); gameAreaContext.stroke(); } // Schwarzer Rahmen (wie vorher) gameAreaContext.strokeStyle = '#000000'; gameAreaContext.strokeRect(0, 0, gameAreaWidth, gameAreaHeight); }
Um die Steuerung auf der Website unterhalb des Spielfelds anzeigen zu lassen, muss in der html-Datei beispielsweise folgendes verändert werden:
<body> Speed: <input type="number" id="gameSpeed" value="5" min="1" max="9" step="1" /> <input type="button" value="Start" id="gameStart" /> <input type="button" value="Schritt für Schritt" id="manualStep" /> <br> <br> <canvas id="gameArea"></canvas> <br> <script src="app.js"></script> <button id="moveUp">Hoch</button> <br> <button id="moveLeft">links</button> <button id="moveRight">rechts </button> <br> <button id="moveDown">runter</button> </body>
und in der app.js Datei: Hier muss bei den Variablen noch für jede der vier Richtungen eine Variable dazugefügt werden.
... timer = {}, moveDown = {}, moveUp = {}, moveLeft = {}, moveRight= {};
Danach muss auch die funktion initElement() erweitert werden.
function initElement() { gameStart = document.querySelector('#gameStart'); gameSpeed = document.querySelector('#gameSpeed'); gameArea = document.querySelector('#gameArea'); manualStep = document.querySelector('#manualStep'); moveDown = document.querySelector('#moveDown'); moveUp = document.querySelector('#moveUp'); moveLeft = document.querySelector('#moveLeft'); moveRight = document.querySelector('#moveRight');
zudem muss auch die Funktion initEvent() vervollständigt werden:
function initEvent() { gameStart.addEventListener('click', onStartGame); manualStep.addEventListener('click', stepOnClick) window.addEventListener('keydown', changeDirection); moveDown.addEventListener('click', function() { if (snakeDirection != 'up') snakeDirection = 'down'; }); moveLeft.addEventListener('click', function() { if (snakeDirection != 'right') snakeDirection = 'left'; }); moveRight.addEventListener('click', function() { if (snakeDirection != 'left') snakeDirection = 'right'; }); moveUp.addEventListener('click', function() { if (snakeDirection != 'down') snakeDirection = 'up'; }); }
</WRAP>