From 55bfd6e774558ee269651acd9b3166c580908048 Mon Sep 17 00:00:00 2001 From: clb92 Date: Tue, 5 Jul 2016 21:02:51 +0200 Subject: [PATCH] Initial commit --- css/styles.css | 77 +++++++++++++++++++++++++ index.html | 20 +++++++ js/canvas.class.js | 68 ++++++++++++++++++++++ js/game.class.js | 127 ++++++++++++++++++++++++++++++++++++++++++ js/resources.class.js | 68 ++++++++++++++++++++++ js/snake.class.js | 101 +++++++++++++++++++++++++++++++++ js/snake.js | 31 +++++++++++ 7 files changed, 492 insertions(+) create mode 100644 css/styles.css create mode 100644 index.html create mode 100644 js/canvas.class.js create mode 100644 js/game.class.js create mode 100644 js/resources.class.js create mode 100644 js/snake.class.js create mode 100644 js/snake.js diff --git a/css/styles.css b/css/styles.css new file mode 100644 index 0000000..82df999 --- /dev/null +++ b/css/styles.css @@ -0,0 +1,77 @@ +* { + margin: 0; + padding: 0; + font-family: sans-serif; +} + +html, body { + height: 100%; + background-color: #333; +} + +.error { + position: absolute; + float: left; + top: 10%; + width: 100%; + font-size: 20pt; + color: #333; + text-align: center; + z-index: 100; + color: red; +} + +#gameCanvas { + position: absolute; + float: left; + width: 100%; + height: 100%; + z-index: 99; + /* filter: blur(40px); + -webkit-filter: blur(40px); */ + transition: all .1s ease; + -webkit-transition: all .1s ease; + -moz-transition: all .1s ease; +} + +#popup-text { + position: absolute; + float: left; + top: 40%; + width: 100%; + font-size: 42pt; + color: #333; + text-align: center; + z-index: 100; + filter: blur(0px); + -webkit-filter: blur(0px); + transition: all .5s ease; + -webkit-transition: all .5s ease; + -moz-transition: all .5s ease; +} + +#overlay { + position: absolute; + float: left; + height: 100%; + width: 100%; + z-index: 102; + opacity: 1; + background-color: #333; + transition: all 1s ease; + -webkit-transition: all 1s ease; + -moz-transition: all 1s ease; +} + +.hidden { + filter: blur(40px) !important; + -webkit-filter: blur(40px) !important; + opacity: 0 !important; + transition: all .5s ease; + -webkit-transition: all .5s ease; + -moz-transition: all .5s ease; +} + +.hidden-overlay { + opacity: 0 !important; +} \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..bf85aa0 --- /dev/null +++ b/index.html @@ -0,0 +1,20 @@ + + + + Snake + + + + + + + + + + +

Your browser does not support HTML5 Canvas!

+
+ +
+ + \ No newline at end of file diff --git a/js/canvas.class.js b/js/canvas.class.js new file mode 100644 index 0000000..8059679 --- /dev/null +++ b/js/canvas.class.js @@ -0,0 +1,68 @@ +/** + * Canvas class + */ +var Canvas = function(game, canvasId) { + this.game = game; + this.canvas = document.getElementById(canvasId); + this.context = this.canvas.getContext("2d"); + this.canvas.setAttribute('height', window.innerHeight); + this.canvas.setAttribute('width', window.innerWidth); + this.color = "lightgrey"; + this.clear(); + this.prep(); +} + +Canvas.prototype.drawAll = function() { + for (var h = 0; h < this.game.grid.height; h++) { + for (var w = 0; w < this.game.grid.width; w++) { + this.context.fillStyle = this.color; + this.context.fillRect(w * this.game.gridSize, h * this.game.gridSize, this.game.gridSize, this.game.gridSize); + + for (var i in this.game.snake.locations) { + if (this.game.snake.locations[i][0] === w && this.game.snake.locations[i][1] === h) { + this.context.fillStyle = "purple"; + this.context.fillRect(w * this.game.gridSize, h * this.game.gridSize, this.game.gridSize, this.game.gridSize); + } + } + } + } +} + +Canvas.prototype.setTile = function(type, x, y) { + switch (type) { + case ('board'): + this.context.fillStyle = this.color; + break; + case ('snake'): + this.context.fillStyle = "purple"; + break; + case ('food'): + this.context.fillStyle = "green"; + break; + case ('death'): + this.context.fillStyle = "red"; + break; + case ('faster'): + this.context.fillStyle = "#708BF4"; + break; + case ('slower'): + this.context.fillStyle = "#3135C4"; + break; + case ('bonus'): + this.context.fillStyle = "gold"; + break; + default: + this.context.fillStyle = this.color; + break; + } + this.context.fillRect(x * this.game.gridSize, y * this.game.gridSize, this.game.gridSize, this.game.gridSize); +} + +Canvas.prototype.prep = function() { + this.context.fillStyle = this.color; + this.context.fillRect(0, 0, this.canvas.width, this.canvas.height); +} + +Canvas.prototype.clear = function() { + this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); +} \ No newline at end of file diff --git a/js/game.class.js b/js/game.class.js new file mode 100644 index 0000000..e1de6aa --- /dev/null +++ b/js/game.class.js @@ -0,0 +1,127 @@ +/** + * Game class + */ +var Game = function() { + this.gameover = false; + this.paused = true; + this.gameLoop = null; + this.gameLoopCount = 0; + this.score = 0; + this.speedNormal = 80; + this.speedModifierNormal = 1; + this.speedModifier = 1; + this.effects = { + bonus: 0, + speedChange: 0 + }; + this.gridSize = 20; + this.grid = { + width: 0, + height: 0 + }; + this.canvas = new Canvas(this, "gameCanvas"); + this.initGrid(); + this.snake = new Snake(this); + this.resources = new Resources(this); +} + +Game.prototype.initGrid = function() { + this.grid.width = Math.floor(this.canvas.canvas.width / this.gridSize); + this.grid.height = Math.floor(this.canvas.canvas.height / this.gridSize); +} + +Game.prototype.start = function() { + this.paused = false; + /* var parent = this; + this.gameLoop = setInterval(function(){ + parent.gameLoopCount++; + if (parent.gameLoopCount % (100 / parent.resources.droprateModifier) === 0 || parent.gameLoopCount === 1) { + parent.resources.dropRandom(); + } + if (parent.effects.speedChange > 0) { + parent.effects.speedChange--; + } else { + parent.speedModifier = parent.speedModifierNormal; + } + parent.update(); + }, 80 / this.speedModifier); */ + + var parent = this; + var interval = this.speedNormal / this.speedModifier; + + function gameLoop() { + if (!parent.paused) { + parent.gameLoopCount++; + if (parent.gameLoopCount % (150 / parent.resources.droprateModifier) === 0 || parent.gameLoopCount === 1) { + parent.resources.dropRandom(); + } + if (parent.effects.speedChange > 0) { + parent.effects.speedChange--; + } else { + parent.speedModifier = parent.speedModifierNormal; + } + parent.update(); + } + interval = parent.speedNormal / parent.speedModifier; + setTimeout(gameLoop, interval); + } + setTimeout(gameLoop, interval); +} + +Game.prototype.update = function() { + this.snake.move(); +} + +Game.prototype.togglePause = function() { + this.paused = (this.paused ? false : true); + if (this.paused) { + //clearInterval(this.gameLoop); + this.canvas.canvas.style.filter = "blur(40px)"; + document.getElementById("popup-text").textContent = "Paused!"; + document.getElementById("popup-text").removeAttribute("class"); + } else { + this.canvas.canvas.style.filter = "blur(0px)"; + document.getElementById("popup-text").setAttribute("class", "hidden"); + this.start(); + } +} + +Game.prototype.applyEffect = function(effect) { + console.log("Effect pickup: " + effect); + switch (effect) { + case ('food'): + console.log("food"); + this.score++; + this.snake.embiggen(1); + break; + case ('death'): + console.log("death"); + this.end(); + break; + case ('faster'): + console.log("faster"); + this.speedModifier = 1.7; + this.effects.speedChange = 150; + break; + case ('slower'): + console.log("slower"); + this.speedModifier = .6; + this.effects.speedChange = 100; + break; + case ('bonus'): + console.log("bonus"); + this.score = this.score + 15; + this.snake.embiggen(5); + break; + } + console.log(this); +} + +Game.prototype.end = function() { + this.gameover = true; + clearInterval(this.gameLoop); + this.canvas.canvas.style.transition = "all 1s ease-out"; + this.canvas.canvas.style.filter = "blur(20px)"; + document.getElementById("popup-text").textContent = "Game over!"; + document.getElementById("popup-text").removeAttribute("class"); +} \ No newline at end of file diff --git a/js/resources.class.js b/js/resources.class.js new file mode 100644 index 0000000..3cd331e --- /dev/null +++ b/js/resources.class.js @@ -0,0 +1,68 @@ +/** + * Resources class + */ +var Resources = function(game) { + this.game = game; + this.droprateModifier = 5; + this.maxDrops = 100; + this.types = [ + 'food', + 'food', + 'food', + 'food', + 'food', + 'food', + 'food', + 'food', + 'food', + 'food', + 'food', + 'food', + 'food', + 'food', + 'food', + 'food', + 'bonus', + 'bonus', + 'death', + 'death', + 'death', + 'faster', + 'faster', + 'faster', + 'slower', + 'slower' + ]; + this.locations = []; +} + +Resources.prototype.checkLocation = function(x, y) { + for (var i = 0; i < this.locations.length; i++) { + if (this.locations[i][0] === x) { + for (var i = 0; i < this.locations.length; i++) { + if (this.locations[i][0] === x && this.locations[i][1] === y) { + return this.locations[i][2]; + } + } + } + } + return null; +} + +Resources.prototype.dropRandom = function() { + if (!this.game.paused) { + if (this.locations.length < this.maxDrops) { + var randDrop = this.getRandomInt(0, this.types.length - 1); + var randX = this.getRandomInt(0, this.game.grid.width - 1); + var randY = this.getRandomInt(0, this.game.grid.height - 1); + + this.game.canvas.setTile(this.types[randDrop], randX, randY); + + this.locations.push([randX, randY, this.types[randDrop]]); + } + } +} + +Resources.prototype.getRandomInt = function(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; +} \ No newline at end of file diff --git a/js/snake.class.js b/js/snake.class.js new file mode 100644 index 0000000..418f296 --- /dev/null +++ b/js/snake.class.js @@ -0,0 +1,101 @@ +/** + * Snake class + */ +var Snake = function(game) { + this.game = game; + this.length = 3; + this.justEaten = 0; + this.nextDirection = 'up'; + this.previousDirection = 'up'; + this.locations = []; + for (var i = 0; i < this.length; i++) { + this.locations[i] = [Math.floor(game.grid.width / 2), Math.floor(game.grid.height / 2) + i]; + } +} + +Snake.prototype.changeDirection = function(direction = '') { + if (direction !== '') { + switch (this.previousDirection) { + case ('up'): + this.nextDirection = (direction === 'down' ? this.nextDirection : direction); + break; + case ('down'): + this.nextDirection = (direction === 'up' ? this.nextDirection : direction); + break; + case ('left'): + this.nextDirection = (direction === 'right' ? this.nextDirection : direction); + break; + case ('right'): + this.nextDirection = (direction === 'left' ? this.nextDirection : direction); + break; + } + } +} + +Snake.prototype.move = function() { + if (!this.game.paused && !this.game.gameover) { + switch (this.nextDirection) { + case ('up'): + var newX = this.locations[0][0]; + var newY = this.locations[0][1] - 1; + break; + case ('down'): + var newX = this.locations[0][0]; + var newY = this.locations[0][1] + 1; + break; + case ('left'): + var newX = this.locations[0][0] - 1; + var newY = this.locations[0][1]; + break; + case ('right'): + var newX = this.locations[0][0] + 1; + var newY = this.locations[0][1]; + break; + default: + break; + } + this.previousDirection = this.nextDirection; + + if (newX > this.game.canvas.width) { + newX = 1; + } + if (newX < this.game.canvas.width) { + newX = this.game.canvas.width - 1; + } + if (newY > this.game.canvas.height) { + newY = 1; + } + if (newY < this.game.canvas.height) { + newY = this.game.canvas.height - 1; + } + + var effect = this.game.resources.checkLocation(newX, newY); + if (effect !== null) { + this.game.applyEffect(effect); + } + + for (var i = 0; i < this.locations.length; i++) { + if (this.locations[i][0] === newX) { + for (var i = 0; i < this.locations.length; i++) { + if (this.locations[i][0] === newX && this.locations[i][1] === newY) { + this.game.end(); + } + } + } + } + + if (this.justEaten > 0) { + this.justEaten--; + } else { + this.game.canvas.setTile('board', this.locations[this.locations.length - 1][0], this.locations[this.locations.length - 1][1]); + this.locations.splice(this.locations.length - 1, 1); + } + + this.locations.unshift([newX, newY]); + this.game.canvas.setTile('snake', this.locations[0][0], this.locations[0][1]); + } +} + +Snake.prototype.embiggen = function(count) { + this.justEaten = count; +} \ No newline at end of file diff --git a/js/snake.js b/js/snake.js new file mode 100644 index 0000000..99b74f8 --- /dev/null +++ b/js/snake.js @@ -0,0 +1,31 @@ +var init = function () { + var game = new Game(); + game.canvas.canvas.style.filter = "blur(40px)"; + game.canvas.drawAll(); + + setTimeout(function(){ + document.getElementById("overlay").setAttribute("class", "hidden-overlay"); + }, 300); + + document.onkeydown = checkKey; + function checkKey(e) { + e = e || window.event; + if (e.keyCode == '38') { // up arrow + game.snake.changeDirection((game.paused || game.gameover ? '' : 'up')); + } else if (e.keyCode == '40') { // down arrow + game.snake.changeDirection((game.paused || game.gameover ? '' : 'down')); + } else if (e.keyCode == '37') { // left arrow + game.snake.changeDirection((game.paused || game.gameover ? '' : 'left')); + } else if (e.keyCode == '39') { // right arrow + game.snake.changeDirection((game.paused || game.gameover ? '' : 'right')); + } else if (e.keyCode == '32' || e.keyCode == '27' || e.keyCode == '80') { // spacebar or escape or p + if (!game.gameover) { + game.togglePause(); + } else { + location.reload(); + } + } + } +}; + +window.addEventListener('load', init); \ No newline at end of file