From a16a01e41748637245474f3d5d051f8de5695cbc Mon Sep 17 00:00:00 2001 From: h7x4 Date: Wed, 19 Feb 2020 15:34:19 +0100 Subject: [PATCH 1/2] Work 19. Feb --- html/tasks/chapter_10/snake/oppgave.html | 6 + html/tasks/chapter_10/snake/script.js | 137 +++++++++++++++++------ 2 files changed, 109 insertions(+), 34 deletions(-) diff --git a/html/tasks/chapter_10/snake/oppgave.html b/html/tasks/chapter_10/snake/oppgave.html index 40fb8d5..885f9e4 100755 --- a/html/tasks/chapter_10/snake/oppgave.html +++ b/html/tasks/chapter_10/snake/oppgave.html @@ -16,6 +16,12 @@ + score: Highscore: +
+ + + +
diff --git a/html/tasks/chapter_10/snake/script.js b/html/tasks/chapter_10/snake/script.js index aaf8794..d3aecc8 100755 --- a/html/tasks/chapter_10/snake/script.js +++ b/html/tasks/chapter_10/snake/script.js @@ -1,26 +1,27 @@ -// @ts-check - /* Initialize variables */ const pixelSize = 20; //Cannot be odd -const pixelAmount = 20; +let pixelAmount = 20; +let score = 0; +if (localStorage.highscore) { + var highscore = localStorage.highscore; //TODO: global let inside if statement? +} else { + highscore = 0; +} /* Register HTML DOM elements by variables */ const canvas = document.getElementById('game'); -const game = canvas.getContext('2d'); -const startButton = document.getElementById('start'); - -/* Add event listeners */ -document.addEventListener('keydown', updateDirection, false); -startButton.addEventListener('click', gameLoop, false); +const ctx = canvas.getContext('2d'); +const startButton = document.getElementById('start'); //TODO: Add canvas size selector, score, higscore, +const pixelAmountInput = document.getElementById('pixelAmount'); +const pixelAmountForm = document.getElementById('pixelAmountForm'); /* Initialize HTML */ canvas.style.display = 'block'; -game.canvas.width = game.canvas.height = pixelSize * pixelAmount; +ctx.canvas.width = ctx.canvas.height = (pixelAmount + 1) * pixelSize; canvas.style.backgroundColor = '#ffffff'; /* Snake object */ const snake = { - speed: 5, //in FPS direction: 'right', color: '#00ff00', tail: [ @@ -32,21 +33,22 @@ const snake = { /* Draw the snake by the tail array */ draw() { - game.fillStyle = this.color; + ctx.fillStyle = this.color; + + const clearPosition = this.tail.pop().map(point => point * pixelSize); + ctx.clearRect(clearPosition[0], clearPosition[1], pixelSize, pixelSize); for (let tailPoint = 0; tailPoint < this.tail.length; tailPoint++) { /* Correct tailpoint x and y to actual size */ const realPosition = this.tail[tailPoint].map(point => point * pixelSize); - game.fillRect(realPosition[0], realPosition[1], pixelSize, pixelSize); + ctx.fillRect(realPosition[0], realPosition[1], pixelSize, pixelSize); } }, /* Generate the next tail array */ updateTail() { - const realPosition = this.tail.pop().map(point => point * pixelSize); - game.clearRect(realPosition[0], realPosition[1], pixelSize, pixelSize); - + //Add new point to tail based on snake direction switch (this.direction) { case 'left': this.tail.unshift([this.tail[0][0] - 1, this.tail[0][1]]); @@ -62,46 +64,111 @@ const snake = { break; } }, + + tailCrossing() { + return new Set(this.tail).size !== this.tail.length; //TODO: fix function + }, }; /* Apple object */ const apple = { - position: [20, 20], + position: [Math.floor(pixelAmount / 2), Math.floor(pixelAmount / 2)], color: 'red', /* Generate new coordinates */ - generate() { - this.position.map(() => Math.floor(Math.random() * pixelAmount)); + generatePosition() { + this.position = this.position.map( + () => Math.floor(Math.random() * pixelAmount) //TODO: Don't put the apple on top of the snake + ); + console.debug(`%cApple position: ${this.position}`, 'color: red'); }, /* Draw the apple */ draw() { const realPosition = this.position.map(point => point * pixelSize); - game.fillStyle = this.color; - game.fillRect(realPosition[0], realPosition[1], pixelSize, pixelSize); + ctx.fillStyle = this.color; + ctx.fillRect(realPosition[0], realPosition[1], pixelSize, pixelSize); }, }; -/* Wrapper function for gameloop */ -function gameLoop() { - /* Slow down loop by snake speed*/ +/* Handles everything that happens on the canvas */ +const game = { + fps: 5, + over: false, + + /* Game init function */ + init() { + apple.draw(); + }, + + /* Game loop function */ + loop() { + /* Draw snake */ + snake.updateTail(); + snake.draw(); + + if (JSON.stringify(snake.tail[0]) === JSON.stringify(apple.position)) { + console.debug('Snake ate apple'); + score += 1; + snake.updateTail(); + apple.generatePosition(); + apple.draw(); + } + if ( + snake.tail[0][0] > pixelAmount || + snake.tail[0][1] > pixelAmount || + snake.tail[0][0] < 0 || + snake.tail[0][1] < 0 || + snake.tailCrossing() + ) { + this.over = true; + } + }, +}; + +/* Wrapper function requesting a gameloop */ +function getLoop() { + /* Slow down loop by game fps */ setTimeout(() => { - window.requestAnimationFrame(gameLoop); - gameUpdate(); - }, 1000 / snake.speed); + window.requestAnimationFrame(getLoop); + game.loop(); + + if (game.over) { + console.debug('Game over'); //TODO: Exit game loop properly + + if (score > highscore) { + console.debug('New highcore'); + highscore = score; + window.localStorage.setItem('highscore', highscore); + } + } + }, 1000 / game.fps); } -/* Function that is being run each tick */ -function gameUpdate() { - /* Draw snake */ - snake.draw(); - snake.updateTail(); +/* Add event listeners */ +document.addEventListener('keydown', updateDirection, false); +startButton.addEventListener( + 'click', + () => { + game.init(); + getLoop(); + }, + false +); +pixelAmountForm.addEventListener('submit', updatePixelAmount, false); - if (snake.tail[0] === apple.position) { - } +/* Updates size of canvas */ +function updatePixelAmount(evt) { + evt.preventDefault(); + pixelAmount = parseInt(pixelAmountInput.value); + console.debug('Updated canvas size'); + ctx.canvas.width = ctx.canvas.height = (pixelAmount + 1) * pixelSize; } +/* Clear higscore from localStorage */ +const clearHighscore = () => (localStorage.highscore = 0); + /* Update direction for snake */ function updateDirection(evt) { const key = evt.code; @@ -133,5 +200,7 @@ function updateDirection(evt) { snake.direction = 'down'; } break; + + //TODO: Add pause function } } From caa65726b934feffff3a00d39ddabb47de64639c Mon Sep 17 00:00:00 2001 From: h7x4 Date: Thu, 20 Feb 2020 10:24:21 +0100 Subject: [PATCH 2/2] Work 20. Feb 2020 --- html/tasks/chapter_10/snake/oppgave.html | 1 + html/tasks/chapter_10/snake/script.js | 154 +++++++++++++++++------ 2 files changed, 116 insertions(+), 39 deletions(-) diff --git a/html/tasks/chapter_10/snake/oppgave.html b/html/tasks/chapter_10/snake/oppgave.html index 885f9e4..1398363 100755 --- a/html/tasks/chapter_10/snake/oppgave.html +++ b/html/tasks/chapter_10/snake/oppgave.html @@ -16,6 +16,7 @@ + score: Highscore:
diff --git a/html/tasks/chapter_10/snake/script.js b/html/tasks/chapter_10/snake/script.js index d3aecc8..4f3003c 100755 --- a/html/tasks/chapter_10/snake/script.js +++ b/html/tasks/chapter_10/snake/script.js @@ -2,8 +2,8 @@ const pixelSize = 20; //Cannot be odd let pixelAmount = 20; let score = 0; -if (localStorage.highscore) { - var highscore = localStorage.highscore; //TODO: global let inside if statement? +if (window.localStorage.highscore) { + var highscore = window.localStorage.highscore; //TODO: global let inside if statement? } else { highscore = 0; } @@ -11,10 +11,16 @@ if (localStorage.highscore) { /* Register HTML DOM elements by variables */ const canvas = document.getElementById('game'); const ctx = canvas.getContext('2d'); -const startButton = document.getElementById('start'); //TODO: Add canvas size selector, score, higscore, +const startButton = document.getElementById('start'); +const resetButton = document.getElementById('reset'); +const scoreSpan = document.getElementById('score'); +const highscoreSpan = document.getElementById('highscore'); const pixelAmountInput = document.getElementById('pixelAmount'); const pixelAmountForm = document.getElementById('pixelAmountForm'); +scoreSpan.innerHTML = score; +highscoreSpan.innerHTML = highscore; + /* Initialize HTML */ canvas.style.display = 'block'; ctx.canvas.width = ctx.canvas.height = (pixelAmount + 1) * pixelSize; @@ -30,21 +36,7 @@ const snake = { [1, 0], [0, 0], ], - - /* Draw the snake by the tail array */ - draw() { - ctx.fillStyle = this.color; - - const clearPosition = this.tail.pop().map(point => point * pixelSize); - ctx.clearRect(clearPosition[0], clearPosition[1], pixelSize, pixelSize); - - for (let tailPoint = 0; tailPoint < this.tail.length; tailPoint++) { - /* Correct tailpoint x and y to actual size */ - const realPosition = this.tail[tailPoint].map(point => point * pixelSize); - - ctx.fillRect(realPosition[0], realPosition[1], pixelSize, pixelSize); - } - }, + deadTail: [0, 0], /* Generate the next tail array */ updateTail() { @@ -63,6 +55,27 @@ const snake = { this.tail.unshift([this.tail[0][0], this.tail[0][1] + 1]); break; } + + this.deadTail = this.tail.pop(); + }, + + /* Draw the snake by the tail array */ + draw() { + ctx.fillStyle = this.color; + + const clearPosition = this.deadTail.map(point => point * pixelSize); + ctx.clearRect(clearPosition[0], clearPosition[1], pixelSize, pixelSize); + + for (let tailPoint = 0; tailPoint < this.tail.length; tailPoint++) { + /* Correct tailpoint x and y to actual size */ + const realPosition = this.tail[tailPoint].map(point => point * pixelSize); + + ctx.fillRect(realPosition[0], realPosition[1], pixelSize, pixelSize); + } + }, + + addTail() { + this.tail.push[this.deadTail]; }, tailCrossing() { @@ -75,11 +88,14 @@ const apple = { position: [Math.floor(pixelAmount / 2), Math.floor(pixelAmount / 2)], color: 'red', + /* Sets position to the middle based on pixelAmount */ + setStartPosition() { + this.position = [Math.floor(pixelAmount / 2), Math.floor(pixelAmount / 2)]; + }, + /* Generate new coordinates */ generatePosition() { - this.position = this.position.map( - () => Math.floor(Math.random() * pixelAmount) //TODO: Don't put the apple on top of the snake - ); + this.position = game.getClearSpotRandom(); //TODO: Switch between the functions based on how much the snake has eaten console.debug(`%cApple position: ${this.position}`, 'color: red'); }, @@ -95,7 +111,8 @@ const apple = { /* Handles everything that happens on the canvas */ const game = { fps: 5, - over: false, + hasEnded: false, + isPaused: false, /* Game init function */ init() { @@ -108,9 +125,10 @@ const game = { snake.updateTail(); snake.draw(); - if (JSON.stringify(snake.tail[0]) === JSON.stringify(apple.position)) { + if (snake.tail[0].toString() === apple.position.toString()) { console.debug('Snake ate apple'); score += 1; + scoreSpan.innerHTML = score; snake.updateTail(); apple.generatePosition(); apple.draw(); @@ -122,28 +140,84 @@ const game = { snake.tail[0][1] < 0 || snake.tailCrossing() ) { - this.over = true; + this.hasEnded = true; } }, + + reset() { + /*TODO: get board size from localstorage */ + snake.tail = [ + [3, 0], + [2, 0], + [1, 0], + [0, 0], + ]; + snake.direction = 'right'; + apple.setStartPosition(); + game.hasEnded = false; + ctx.fillStyle = '#ffffff'; + ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height); + }, + + /* Function to determine whether a coordinate hits the snake + * Retuns a bool + */ + hitsSnake(coordinate) { + return snake.tail + .map(snakeCoordinate => snakeCoordinate.toString()) //TODO: Rewrite + .toString() + .includes(coordinate.toString()); + }, + + /* Function to be used if the snake is covering a small part of the map + * Returns a coordinate array + */ + getClearSpotRandom() { + while (true) { + const coordinate = Array.from({length: 2}, () => + Math.floor(Math.random() * pixelAmount) + ); + + if (!this.hitsSnake(coordinate)) { + return coordinate; + } + } + }, + + /* Function to be used if the snake is covering a big part of the map + * Returns a coordinate array + */ + getClearSpotForce() { + clearSpots = []; + + for (let x = 0; x < pixelAmount; x++) { + for (let y = 0; y < pixelAmount; y++) { + if (!this.hitsSnake([x, y])) { + clearSpots.push([x, y]); + } + } + } + return clearSpots[Math.floor(Math.random() * clearSpots.length)]; + }, }; /* Wrapper function requesting a gameloop */ function getLoop() { /* Slow down loop by game fps */ - setTimeout(() => { - window.requestAnimationFrame(getLoop); - game.loop(); + if (!game.hasEnded) { + setTimeout(() => { + window.requestAnimationFrame(getLoop); + game.loop(); + }, 1000 / game.fps); + } else { + console.debug('Game over'); - if (game.over) { - console.debug('Game over'); //TODO: Exit game loop properly - - if (score > highscore) { - console.debug('New highcore'); - highscore = score; - window.localStorage.setItem('highscore', highscore); - } + if (score > highscore) { + console.debug('New highcore'); + highscore = score; + window.localStorage.setItem('highscore', highscore); } - }, 1000 / game.fps); + } } /* Add event listeners */ @@ -156,6 +230,7 @@ startButton.addEventListener( }, false ); +resetButton.addEventListener('click', game.reset, false); pixelAmountForm.addEventListener('submit', updatePixelAmount, false); /* Updates size of canvas */ @@ -164,10 +239,11 @@ function updatePixelAmount(evt) { pixelAmount = parseInt(pixelAmountInput.value); console.debug('Updated canvas size'); ctx.canvas.width = ctx.canvas.height = (pixelAmount + 1) * pixelSize; + apple.setStartPosition(); } /* Clear higscore from localStorage */ -const clearHighscore = () => (localStorage.highscore = 0); +const clearHighscore = () => (window.localStorage.highscore = 0); /* Update direction for snake */ function updateDirection(evt) { @@ -200,7 +276,7 @@ function updateDirection(evt) { snake.direction = 'down'; } break; - - //TODO: Add pause function } + + //TODO: Add pause function }