Skip to content

Instantly share code, notes, and snippets.

@1995eaton
Created September 16, 2014 18:00
Show Gist options
  • Save 1995eaton/469f5d5aad9163e6b2d5 to your computer and use it in GitHub Desktop.
Save 1995eaton/469f5d5aad9163e6b2d5 to your computer and use it in GitHub Desktop.
Classic snake game in JavaScript + HTML5 Canvas
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title></title>
<meta name="description" content="">
<meta name="author" content="">
<style>
#canvas {
border: 1px solid;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
<script>
var WIDTH = 70;
var HEIGHT = 70;
var SIZE = 10;
var LEFT = 37,
RIGHT = 39,
UP = 38,
DOWN = 40;
var Grid = function(width, height) {
this.width = width;
this.height = height;
this.data = Array.apply(null, new Array(height))
.map(function() { return new Uint8Array(width); });
};
Grid.prototype = {
set: function(x, y, v) {
if (this.data[y]) {
this.data[y][x] = v;
}
},
at: function(x, y) {
if (this.data[y] === void 0 || this.data[y][x] === void 0) {
return 1;
}
return this.data[y][x];
}
};
var Snake = function(x, y) {
this.data = [{
x: x,
y: y
}];
this.direction = LEFT;
this.lastDirection = LEFT;
this.wait = 0;
};
Snake.prototype = {
get head() {
return this.data[0];
},
get tail() {
return this.data[this.data.length - 1];
},
push: function(n) {
this.wait = n;
},
step: function() {
var head = this.head;
var next = {
x: head.x,
y: head.y
};
switch (this.direction) {
case LEFT:
next.x--;
break;
case RIGHT:
next.x++;
break;
case UP:
next.y--;
break;
default:
next.y++;
}
this.lastDirection = this.direction;
this.data.unshift(next);
if (this.wait === 0) {
this.data.pop();
} else {
this.wait--;
}
}
};
var Game = (function() {
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d'),
grid = new Grid(WIDTH, HEIGHT),
snake = new Snake(~~(WIDTH / 2), ~~(HEIGHT / 2), grid);
snake.push(3);
canvas.width = WIDTH * SIZE;
canvas.height = HEIGHT * SIZE;
var fill = function(x, y) {
context.fillRect(x * SIZE, y * SIZE, SIZE, SIZE);
};
var clear = function(x, y) {
context.clearRect(x * SIZE, y * SIZE, SIZE, SIZE);
};
var dot = (function() {
var _ = {
next: function() {
_.x = ~~(Math.random() * WIDTH);
_.y = ~~(Math.random() * HEIGHT);
while (grid.at(_.x, _.y) === 1) {
_.next();
}
fill(_.x, _.y);
}
};
_.next();
return _;
})();
var id = window.setInterval(render, 1000 / 20);
function render() {
var x, y;
if (snake.wait === 0) {
var tail = snake.tail;
x = tail.x;
y = tail.y;
clear(x, y);
grid.set(x, y, 0);
}
snake.step();
var head = snake.head;
x = head.x;
y = head.y;
if (grid.at(x, y) === 1) {
window.clearInterval(id);
}
grid.set(x, y, 1);
fill(x, y);
if (snake.head && dot.x === snake.head.x && dot.y === snake.head.y) {
dot.next();
snake.push(5);
}
};
window.addEventListener('keydown', function(event) {
switch (event.which) {
case LEFT:
if (snake.lastDirection !== RIGHT) {
snake.direction = LEFT;
}
break;
case RIGHT:
if (snake.lastDirection !== LEFT) {
snake.direction = RIGHT;
}
break;
case UP:
if (snake.lastDirection !== DOWN) {
snake.direction = UP;
}
break;
case DOWN:
if (snake.lastDirection !== UP) {
snake.direction = DOWN;
}
break;
}
});
})();
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment