diff --git a/index.html b/index.html index 2765af8..1815392 100644 --- a/index.html +++ b/index.html @@ -6,7 +6,6 @@ -

KyFlo Snake

@@ -22,6 +21,8 @@
+

+

diff --git a/sources/js/Game.js b/sources/js/Game.js index 1145588..0f05d5a 100644 --- a/sources/js/Game.js +++ b/sources/js/Game.js @@ -6,44 +6,27 @@ export class Game { /** * Generate a new game of Snake * @param {HTMLCanvasElement} canvas - * @param {[int, int]} size - * @param {directions} direction - * @param {int} snakeSpeed - * @param {int} appleSpeed - * @param {int} lives */ - constructor(canvas, {size = [15, 15], direction = directions.RIGHT, snakeSpeed = 500, appleSpeed = 5000, lives = 3} = {}) { + constructor(canvas) { if (canvas && canvas.nodeName === "CANVAS") this.ctx = canvas.getContext("2d"); else throw new InvalidGameOption("canvas"); - if (size && Array.isArray(size) && size.length === 2 && size.filter(s => typeof s === "number" && s > 0 && s % 1 === 0).length === size.length) - this.size = size; - else - throw new InvalidGameOption("size"); - - if (direction && Object.values(directions).find(([x,y]) => direction[0] === x && direction[1] === y)) - this.direction = this.startDirection = this.lastDirection = direction; - else - throw new InvalidGameOption("direction"); - - if (snakeSpeed && typeof snakeSpeed === "number" && snakeSpeed > 0 && snakeSpeed % 1 === 0) - this.snakeSpeed = snakeSpeed; - else - throw new InvalidGameOption("snakeSpeed"); - - if (appleSpeed && typeof appleSpeed === "number" && appleSpeed > 0 && appleSpeed % 1 === 0) - this.appleSpeed = appleSpeed; - else - throw new InvalidGameOption("appleSpeed"); + this.size = [15, 15]; + this.direction = directions.RIGHT; + this.snakeSpeed = 500; + this.appleSpeed = 5000; + this.lives = 3; this.world = []; this.apple = false; this.score = 0; - this.lives = lives; this.onStart = null; this.onStop = null; + this.onEat = null; + this.onDie = null; + this.onGameOver = null; } /** @@ -62,7 +45,7 @@ export class Game { * Init the canvas */ initCanvas() { - this.ctx.canvas.ownerDocument.addEventListener("keyup", ev => { + this.ctx.canvas.ownerDocument.addEventListener("keydown", ev => { switch (ev.key) { case "ArrowUp": if (this.lastDirection !== directions.DOWN) @@ -146,10 +129,14 @@ export class Game { if (err instanceof GameOver) { this.lives--; if (this.lives <= 0) { - alert(`Game over !\nYour score is: ${this.score}`); + if (this.onGameOver && typeof this.onGameOver === "function") + this.onGameOver(this.score); this.stop(); - } else + } else { + if (this.onDie && typeof this.onDie === "function") + this.onDie(this.lives); this.restart(); + } } else { console.error(err); alert("An error occurred !"); @@ -170,6 +157,8 @@ export class Game { this.snake.eat(); this.apple = false; this.score++; + if (this.onEat && typeof this.onEat === "function") + this.onEat(this.score); } t.type = tiles.SNAKE; } @@ -218,6 +207,41 @@ export class Game { return pos; } + + /** + * Generate a new game of Snake + * @param {[int, int]} size + * @param {directions} direction + * @param {int} snakeSpeed + * @param {int} appleSpeed + * @param {int} lives + */ + load({size = [15, 15], direction = directions.RIGHT, snakeSpeed = 500, appleSpeed = 5000, lives = 3} = {}) { + if (size && Array.isArray(size) && size.length === 2 && size.filter(s => typeof s === "number" && s > 0 && s % 1 === 0).length === size.length) + this.size = size; + else + throw new InvalidGameOption("size"); + + if (direction && Object.values(directions).find(([x,y]) => direction[0] === x && direction[1] === y)) + this.direction = this.startDirection = this.lastDirection = direction; + else + throw new InvalidGameOption("direction"); + + if (snakeSpeed && typeof snakeSpeed === "number" && snakeSpeed > 0 && snakeSpeed % 1 === 0) + this.snakeSpeed = snakeSpeed; + else + throw new InvalidGameOption("snakeSpeed"); + + if (appleSpeed && typeof appleSpeed === "number" && appleSpeed > 0 && appleSpeed % 1 === 0) + this.appleSpeed = appleSpeed; + else + throw new InvalidGameOption("appleSpeed"); + + if (lives && typeof lives === "number" && lives > 0 && lives % 1 === 0) + this.lives = lives; + else + throw new InvalidGameOption("lives"); + } } export class InvalidGameOption extends Error { diff --git a/sources/js/index.js b/sources/js/index.js index 3790915..a5760e2 100644 --- a/sources/js/index.js +++ b/sources/js/index.js @@ -4,7 +4,17 @@ const canvas = document.getElementById("canvas"); const menu = document.getElementById("menu"); const menuLevel = document.querySelector(".menu-level"); const gameZone = document.getElementById("game"); -let game; +const score = document.getElementById("score"); +const lives = document.getElementById("lives"); +const audio = new Audio("sources/sound/main.mp3"); +const startSound = new Audio("sources/sound/onStart.mp3"); +const eatSound = new Audio("sources/sound/onEat.mp3"); +const dieSound = new Audio("sources/sound/onDie.mp3"); +const gameOverSound = new Audio("sources/sound/onGameOver.mp3"); +const game = new Game(canvas); + + +startSound.volume = "0.2"; req.open("GET", "sources/levels.json"); req.onerror = () => console.error("Fail to load XML request"); @@ -16,10 +26,37 @@ req.onload = () => { else levels = null; loadLevels(levels); -} +}; req.send(); +game.onStart = () => { + updateLives(game.lives); + updateScore(game.score); + menu.classList.add("invisible"); + canvas.classList.remove("invisible"); +}; + +game.onStop = () => { + menu.classList.remove("invisible"); + canvas.classList.add("invisible"); +}; + +game.onEat = (score) => { + eatSound.play(); + updateScore(score); +}; + +game.onDie = lives => { + dieSound.play(); + updateLives(lives); +}; + +game.onGameOver = (score) => { + gameOverSound.play(); + alert(`Game over !\nYour score is: ${score}`); +}; + function loadLevels(levels) { if (!levels) { menuLevel.innerHTML = ""; @@ -35,25 +72,28 @@ function loadLevels(levels) { } } -const loadGame = data => { - game = new Game(canvas, data); - - game.onStart = () => { - menu.classList.add("invisible"); - canvas.classList.remove("invisible"); - }; - - game.onStop = () => { - menu.classList.remove("invisible"); - canvas.classList.add("invisible"); - }; - +function loadGame(data) { + game.load(data); game.start(); + startSound.play(); }; +function updateScore(s) { + score.innerText = s; +} + +function updateLives(l) { + lives.innerText = l; +} + document.addEventListener('DOMContentLoaded', function() { M.AutoInit(); - canvas.width = gameZone.offsetWidth; - canvas.height = gameZone.offsetHeight; + canvas.width = gameZone.clientWidth; + canvas.height = gameZone.clientHeight; +}); + +audio.addEventListener("canplaythrough", () => { + audio.volume = 0.1; + audio.play(); }); diff --git a/sources/sound/onDie.mp3 b/sources/sound/onDie.mp3 new file mode 100644 index 0000000..27bfd8f Binary files /dev/null and b/sources/sound/onDie.mp3 differ diff --git a/sources/sound/onEat.mp3 b/sources/sound/onEat.mp3 new file mode 100644 index 0000000..65e634b Binary files /dev/null and b/sources/sound/onEat.mp3 differ diff --git a/sources/sound/onGameOver.mp3 b/sources/sound/onGameOver.mp3 new file mode 100644 index 0000000..3b15a5c Binary files /dev/null and b/sources/sound/onGameOver.mp3 differ diff --git a/sources/sound/onStart.mp3 b/sources/sound/onStart.mp3 new file mode 100644 index 0000000..e12e368 Binary files /dev/null and b/sources/sound/onStart.mp3 differ