<div class="container">
<header class="title">
<h1>JavaScript Snake Game</h1>
<h2 id="score" class="score">Score: </h2>
</header>
</div>
<div class="container">
<section class="overlay">
<div class="gameOverGrid">
<h2 id="gameOver">You lose!</h2>
</div>
<button class="gameOverGrid btn">Play</button>
</section>
<section id="gameBoard"></section>
</div>
/* https://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section { display: block; }
body { line-height: 1; }
ol, ul { list-style: none; }
blockquote, q { quotes: none; }
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
/* Grid */
html {
box-sizing: border-box;
background-color: #000;
}
*, *:before, *:after { box-sizing: inherit; }
.container {
margin: 0 auto;
padding: 0 25px;
text-align: center;
position: relative;
}
.overlay {
position: absolute;
top: 50%;
left: 50%;
width: 25%;
height: 50%;
transform: translate(-50%,-50%);
background-color: rgba(0,0,0,0.5);
border-radius: 5%;
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
}
.title { margin-bottom: 15px; }
#gameBoard, .row {
display: flex;
flex-flow: row wrap;
}
#gameBoard {
width: 600px;
height: 600px;
margin: 0 auto;
border: 4px groove #5657ff;
box-sizing: content-box;
background: #000;
}
.gameOverGrid {
margin: auto;
}
/* Game */
.pixel {
width: 15px;
height: 15px;
box-sizing: border-box;
}
.snakePixel {
background-color: #fa981c;
}
.foodPixel {
background-color: #f59798;
}
#gameOver {
display: none;
font-size: 28px;
color: #de1f25;
}
.pixel:last-child {
border-right: none;
}
.row:last-child .pixel {
border-bottom: none;
}
/* Style */
.btn {
background-color: #f38805;
border-color: 10px solid #da0101;
-webkit-border-radius: 6;
-moz-border-radius: 6;
border-radius: 6px;
font-family: Arial;
color: #ffffff;
font-size: 20px;
font-weight: bold;
text-shadow: 2px 2px 2px #360072;
text-transform: uppercase;
color: #f9e20a;
padding: 10px 20px 10px 20px;
text-decoration: none;
border: 0;
transition: 200ms all ease-out;
}
.btn:hover {
cursor: pointer;
background-color: #8bd5e2;
text-decoration: none;
}
/* Typog */
/*! Typebase.less v0.1.0 | MIT License */
/* Setup */
html {
/* Change default typefaces here */
font-family: serif;
font-size: 137.5%;
-webkit-font-smoothing: antialiased;
}
/* Copy & Lists */
p {
line-height: 1.5rem;
margin-top: 1.5rem;
margin-bottom: 0;
}
ul,
ol {
margin-top: 1.5rem;
margin-bottom: 1.5rem;
}
ul li,
ol li {
line-height: 1.5rem;
}
ul ul,
ol ul,
ul ol,
ol ol {
margin-top: 0;
margin-bottom: 0;
}
blockquote {
line-height: 1.5rem;
margin-top: 1.5rem;
margin-bottom: 1.5rem;
}
/* Headings */
h1,
h2,
h3,
h4,
h5,
h6 {
/* Change heading typefaces here */
font-family: sans-serif;
margin-top: 1.5rem;
margin-bottom: 0;
line-height: 1.5rem;
color: #8bd5e2;
}
h1 {
font-size: 4.242rem;
line-height: 4.5rem;
margin-top: 3rem;
}
h2 {
font-size: 2.828rem;
line-height: 3rem;
margin-top: 3rem;
}
h3 {
font-size: 1.414rem;
}
h4 {
font-size: 0.707rem;
}
h5 {
font-size: 0.4713333333333333rem;
}
h6 {
font-size: 0.3535rem;
}
/* Tables */
table {
margin-top: 1.5rem;
border-spacing: 0px;
border-collapse: collapse;
}
table td,
table th {
padding: 0;
line-height: 33px;
}
/* Code blocks */
code {
vertical-align: bottom;
}
/* Leading paragraph text */
.lead {
font-size: 1.414rem;
}
/* Hug the block above you */
.hug {
margin-top: 0;
}
.score {
margin-top: 0;
font-size: 28px;
color: #e7e513;
}
h1 {
font-size: 56px;
}
/*jslint browser: true*/
/*global $, jQuery, alert*/
var gameBoardSize = 40;
var gamePoints = 0;
var gameSpeed = 100;
$(document).ready(function () {
createBoard();
$(".btn").click(function() {
startGame();
});
});
var Snake = {
position: [[20, 20], [20, 19], [20, 18]], // snake start position
size: 3,
direction: "r",
alive: true
}
var Food = {
position: [],
present: false
}
function createBoard() {
$("#gameBoard").empty();
var size = gameBoardSize;
for (i = 0; i < size; i++) {
$("#gameBoard").append('<div class="row"></div>');
for (j = 0; j < size; j++) {
$(".row:last-child").append('<div class="pixel"></div>');
}
}
}
function moveSnake() {
var head = Snake.position[0].slice();
switch (Snake.direction) {
case 'r':
head[1] += 1;
break;
case 'l':
head[1] -= 1;
break;
case 'u':
head[0] -= 1;
break;
case 'd':
head[0] += 1;
break;
}
// check after head is moved
if (alive(head)) {
// draw head
$(".row:nth-child(" + head[0] + ") > .pixel:nth-child(" + head[1] + ")").addClass("snakePixel");
// draw rest of body loop
for (var i = 0; i < Snake.size; i++) {
$(".row:nth-child(" + Snake.position[i][0] + ") > .pixel:nth-child(" + Snake.position[i][1] + ")").addClass("snakePixel");
}
// if head touches food
if (head.every(function(e,i) {
return e === Food.position[i];
})) {
Snake.size++;
Food.present = false;
gamePoints += 5;
$(".row:nth-child(" + Food.position[0] + ") > .pixel:nth-child(" + Food.position[1] + ")").removeClass("foodPixel");
$("#score").html("Score: "+gamePoints)
if (gamePoints % 16 == 0 && gameSpeed > 10) { gameSpeed -= 5; };
} else {
$(".row:nth-child(" + Snake.position[Snake.size-1][0] + ") > .pixel:nth-child(" + Snake.position[Snake.size-1][1] + ")").removeClass("snakePixel");
Snake.position.pop();
}
Snake.position.unshift(head);
} else {
gameOver();
}
}
function generateFood() {
if (Food.present === false) {
Food.position = [Math.floor((Math.random()*40) + 1), Math.floor((Math.random()*40) + 1)]
Food.present = true;
console.log("Food at: "+Food.position);
$(".row:nth-child(" + Food.position[0] + ") > .pixel:nth-child(" + Food.position[1] + ")").addClass("foodPixel");
}
}
function keyPress() {
$(document).one("keydown", function(key) {
switch(key.which) {
case 37: // left arrow
if (Snake.direction != "r") {Snake.direction = "l";}
break;
case 38: // up arrow
if (Snake.direction != "d") {Snake.direction = "u";}
break;
case 39: // right arrow
if (Snake.direction != "l") {Snake.direction = "r";}
break;
case 40: // down arrow
if (Snake.direction != "u") {Snake.direction = "d";}
break;
}
});
}
function gameLoop() {
setTimeout(function() {
keyPress();
generateFood();
moveSnake();
if (Snake.alive) {gameLoop(); }
}, gameSpeed);
}
function alive(head) {
// head check
if (head[0] < 1 || head[0] > 40 || head[1] < 1 || head[1] > 40) {
return false;
}
// wall collision
if (Snake.position[0][0] < 1 || Snake.position[0][0] > 40 || Snake.position[0][1] < 1 || Snake.position[0][1] > 40) {
return false;
}
// self collision
for (var i = 1; i < Snake.size; i++) {
if ((Snake.position[0]).every(function(element,index) {
return element === Snake.position[i][index];
})) {
return false;
}
}
return true;
}
function gameOver() {
Snake.alive = false;
console.log("Game Over!");
$(".overlay").show();
$("#gameOver").show();
var blink = function() {
$(".row:nth-child(" + Snake.position[0][0] + ") > .pixel:nth-child(" + Snake.position[0][1] + ")").toggleClass("snakePixel");
}
var i = 0;
function blinkLoop() {
blink();
setTimeout(function() {
i++;
if (i < 10) { blinkLoop();}
}, 400);
}
blinkLoop();
}
function startGame() {
// reset game settings
Snake.size = 3;
Snake.position = [[20,20],[20,19],[20,18]];
Snake.direction = "r";
Snake.alive = true;
gameSpeed = 100;
gamePoints = 0;
Food.present = false;
// start game
createBoard();
$(".overlay").hide();
gameLoop();
}
This Pen doesn't use any external CSS resources.