Skip to content

Instantly share code, notes, and snippets.

@mhuggins
Last active June 11, 2021 09:59
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save mhuggins/28c387ebb665c4b73db1d3af61d6dcec to your computer and use it in GitHub Desktop.
Save mhuggins/28c387ebb665c4b73db1d3af61d6dcec to your computer and use it in GitHub Desktop.
Snake.js

Simple snake game in JS.

Unfinished features & unaddressed issues:

  • No collision detection (no win/loss)
  • Pressing two directions in quick succession allows the snake to reverse direction on itself. (This is an issue with the FPS limiting vs. event-driven key handling.)
  • Food can spawn on top of the snake.
<html>
<body>
<canvas id="game" width="400" height="400"></canvas>
<script src="./game.js" type="text/javascript"></script>
</body>
</html>
var KEY_LEFT = 37;
var KEY_UP = 38;
var KEY_RIGHT = 39;
var KEY_DOWN = 40;
var vendors = ["webkit", "moz", "o", "ms"];
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; x++) {
window.requestAnimationFrame = window[vendors[x] + "RequestAnimationFrame"];
window.cancelAnimationFrame = window[vendors[x] + "CancelAnimationFrame"] ||
window[vendors[x] + "CancelRequestAnimationFrame"];
}
function Game(context) {
this.context = context;
this.boardSize = 20;
this.tileSize = 20;
this.fps = 20;
this.segments = [];
this.length = 5;
this.position = { x: this.boardSize / 2, y: this.boardSize / 2 };
this.foodPosition = this._getRandomPosition();
this.direction = { x: 1, y: 0 };
}
Game.prototype.start = function(win) {
document.addEventListener("keydown", function(event) {
switch (event.keyCode) {
case KEY_LEFT:
if (this.direction.x === 0) {
this.direction = { x: -1, y: 0 };
}
break;
case KEY_UP:
if (this.direction.y === 0) {
this.direction = { x: 0, y: -1 };
}
break;
case KEY_RIGHT:
if (this.direction.x === 0) {
this.direction = { x: 1, y: 0 };
}
break;
case KEY_DOWN:
if (this.direction.y === 0) {
this.direction = { x: 0, y: 1 };
}
break;
}
}.bind(this));
this.lastTime = Date.now();
this._loop(win);
};
Game.prototype._loop = function(win) {
var fpsInterval = 1000 / this.fps;
var currentTime = Date.now();
var elapsedTime = currentTime - this.lastTime;
win.requestAnimationFrame(function() {
if (elapsedTime > fpsInterval) {
this._move();
this._draw();
this.lastTime = currentTime - (elapsedTime % fpsInterval);
}
this._loop(win);
}.bind(this));
};
Game.prototype._move = function() {
this.position = { x: this.position.x + this.direction.x, y: this.position.y + this.direction.y };
["x", "y"].forEach(function(direction) {
while (this.position[direction] < 0) {
this.position[direction] += this.boardSize;
}
while (this.position[direction] >= this.boardSize) {
this.position[direction] -= this.boardSize;
}
}.bind(this));
this.segments.push(this.position);
while (this.segments.length > this.length) {
this.segments.shift();
}
if (this.position.x === this.foodPosition.x && this.position.y === this.foodPosition.y) {
this.length++;
this.foodPosition = this._getRandomPosition();
}
};
Game.prototype._draw = function() {
this.context.clearRect(0, 0, this.boardSize * this.tileSize, this.boardSize * this.tileSize);
this.context.fillStyle = "rgb(0, 0, 0)";
this.context.fillRect(0, 0, this.boardSize * this.tileSize, this.boardSize * this.tileSize);
this.context.fillStyle = "rgb(192, 192, 192)";
this.segments.forEach(function(segment) {
this.context.fillRect(segment.x * this.tileSize, segment.y * this.tileSize, this.tileSize, this.tileSize);
}.bind(this));
this.context.fillStyle = "rgb(0, 255, 0)";
this.context.fillRect(this.foodPosition.x * this.tileSize, this.foodPosition.y * this.tileSize, this.tileSize, this.tileSize);
};
Game.prototype._getRandomPosition = function() {
return {
x: Math.floor(Math.random() * this.boardSize),
y: Math.floor(Math.random() * this.boardSize)
};
};
var canvas = document.getElementById("game");
var context = canvas.getContext("2d");
if (context !== null) {
new Game(context).start(window);
} else {
alert("Unable to obtain 2D canvas context.");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment