Add sounds, config loader and the base of score & lives display
This commit is contained in:
parent
829926dddf
commit
4d0c09fa1f
7 changed files with 112 additions and 47 deletions
|
@ -6,7 +6,6 @@
|
|||
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="sources/css/style.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<h1 class="linear-wipe">KyFlo Snake</h1>
|
||||
|
@ -22,6 +21,8 @@
|
|||
<div id="game">
|
||||
<canvas id="canvas" class="invisible"></canvas>
|
||||
</div>
|
||||
<p id="score"></p>
|
||||
<p id="lives"></p>
|
||||
|
||||
<script type="module" src="sources/js/index.js"></script>
|
||||
</body>
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
|
|
BIN
sources/sound/onDie.mp3
Normal file
BIN
sources/sound/onDie.mp3
Normal file
Binary file not shown.
BIN
sources/sound/onEat.mp3
Normal file
BIN
sources/sound/onEat.mp3
Normal file
Binary file not shown.
BIN
sources/sound/onGameOver.mp3
Normal file
BIN
sources/sound/onGameOver.mp3
Normal file
Binary file not shown.
BIN
sources/sound/onStart.mp3
Normal file
BIN
sources/sound/onStart.mp3
Normal file
Binary file not shown.
Reference in a new issue