How to Make a Simple Snake Game in Javascript?
- 时间:2020-09-12 10:17:13
- 分类:网络文摘
- 阅读:122 次
Snake Game (snake eats apple and grows) is a simple and easy to implement game that you can practice when you learn a new programming language. It is not complex, and usually, it can be designed and completed in a day.

simple-snake-game-in-javascript
Drawing the Canvas
You would need a canvas to draw the snake (green body pieces) and the red apple. In the browser, you can define a Game canvas in HTML tag:
1 | <canvas width="400" height="400" id="game"></canvas> |
<canvas width="400" height="400" id="game"></canvas>
Then let’s define a few global variables that we need to use later:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | var context; var canvas; var score = 0; var bestscore = 0; var grid = 16; var count = 0; var snake = { x: 160, y: 160, // snake directin offsets dx: grid, dy: 0, // snake body cells: [], // snake body length, grows when eats an apple maxCells: 4 }; var apple = { x: 320, y: 320 }; |
var context;
var canvas;
var score = 0;
var bestscore = 0;
var grid = 16;
var count = 0;
var snake = {
x: 160,
y: 160,
// snake directin offsets
dx: grid,
dy: 0,
// snake body
cells: [],
// snake body length, grows when eats an apple
maxCells: 4
};
var apple = {
x: 320,
y: 320
};Game Controls
Then on the body onload event, we need to invoke a onload function:
1 | <body onload="windowload()"> |
<body onload="windowload()">
The onload function will be called once the HTML is loaded and the DOM is finished loading. Then, we listen to the keydown event to control the snake. movement.
The additional checks prevent snake from backtracking on itself by checking that it’s not already moving on the same axis (pressing left while moving left won’t do anything, and pressing right while moving left shouldn’t let you collide with your own body).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | function windowload() { canvas = document.getElementById('game'); canvas.setAttribute('tabindex','0'); canvas.focus(); context = canvas.getContext('2d'); // arrow keys to control the snake document.addEventListener('keydown', function(e) { // left arrow key if (e.which === 37 && snake.dx === 0) { snake.dx = -grid; snake.dy = 0; } // up arrow key else if (e.which === 38 && snake.dy === 0) { snake.dy = -grid; snake.dx = 0; } // right arrow key else if (e.which === 39 && snake.dx === 0) { snake.dx = grid; snake.dy = 0; } // down arrow key else if (e.which === 40 && snake.dy === 0) { snake.dy = grid; snake.dx = 0; } }); window.requestAnimationFrame(loop); } |
function windowload() {
canvas = document.getElementById('game');
canvas.setAttribute('tabindex','0');
canvas.focus();
context = canvas.getContext('2d');
// arrow keys to control the snake
document.addEventListener('keydown', function(e) {
// left arrow key
if (e.which === 37 && snake.dx === 0) {
snake.dx = -grid;
snake.dy = 0;
}
// up arrow key
else if (e.which === 38 && snake.dy === 0) {
snake.dy = -grid;
snake.dx = 0;
}
// right arrow key
else if (e.which === 39 && snake.dx === 0) {
snake.dx = grid;
snake.dy = 0;
}
// down arrow key
else if (e.which === 40 && snake.dy === 0) {
snake.dy = grid;
snake.dx = 0;
}
});
window.requestAnimationFrame(loop);
}The window.requestAnimationFrame takes a function call back as a parameter that tells windows to run on painting the next frame. Before the main game loop, we need to define a few helper functions:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | // return a random integer between [min, max) function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min)) + min; } function showScore(score) { document.getElementById('score').innerHTML = score; } function showBestScore(score) { document.getElementById('bestscore').innerHTML = score; } // reset the game function resetGame() { snake.x = 160; snake.y = 160; snake.cells = []; snake.maxCells = 4; snake.dx = grid; snake.dy = 0; score = 0; showScore(score); apple.x = getRandomInt(0, 25) * grid; apple.y = getRandomInt(0, 25) * grid; } |
// return a random integer between [min, max)
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
function showScore(score) {
document.getElementById('score').innerHTML = score;
}
function showBestScore(score) {
document.getElementById('bestscore').innerHTML = score;
}
// reset the game
function resetGame() {
snake.x = 160;
snake.y = 160;
snake.cells = [];
snake.maxCells = 4;
snake.dx = grid;
snake.dy = 0;
score = 0;
showScore(score);
apple.x = getRandomInt(0, 25) * grid;
apple.y = getRandomInt(0, 25) * grid;
}Main Game Loop
In the game loop, we need to recursively tell windows to requestAnimationFrame. Then, clear the canvas and draw the snake body pieces and the apple.
The game-over needs to be triggered if the snake hits the wall, or it collides with its body. When it moves, we can pop one from its tail and push it to the front (head).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | function loop() { requestAnimationFrame(loop); // slow game loop to 15 fps instead of 60 (60/15 = 4) if (++count < 4) { return; } count = 0; context.clearRect(0,0,canvas.width,canvas.height); // move snake by it's velocity snake.x += snake.dx; snake.y += snake.dy; if ((snake.x < 0) || (snake.x >= canvas.width)) { resetGame(); return; } if ((snake.y < 0) || (snake.y >= canvas.height)) { resetGame(); return; } // keep track of where snake has been. front of the array is always the head snake.cells.unshift({x: snake.x, y: snake.y}); // remove cells as we move away from them if (snake.cells.length > snake.maxCells) { snake.cells.pop(); } // draw apple context.fillStyle = 'red'; context.fillRect(apple.x, apple.y, grid-1, grid-1); // draw snake one cell at a time context.fillStyle = 'green'; snake.cells.forEach(function(cell, index) { // drawing 1 px smaller than the grid creates a grid effect in the snake body so you can see how long it is context.fillRect(cell.x, cell.y, grid-1, grid-1); // snake ate apple if (cell.x === apple.x && cell.y === apple.y) { snake.maxCells++; // canvas is 400x400 which is 25x25 grids apple.x = getRandomInt(0, 25) * grid; apple.y = getRandomInt(0, 25) * grid; score ++; bestscore = Math.max(bestscore, score); showBestScore(bestscore); showScore(score); } // check collision with all cells after this one (modified bubble sort) for (var i = index + 1; i < snake.cells.length; i += 1) { // snake occupies same space as a body part. reset game if (cell.x === snake.cells[i].x && cell.y === snake.cells[i].y) { resetGame(); return; } } }); } |
function loop() {
requestAnimationFrame(loop);
// slow game loop to 15 fps instead of 60 (60/15 = 4)
if (++count < 4) {
return;
}
count = 0;
context.clearRect(0,0,canvas.width,canvas.height);
// move snake by it's velocity
snake.x += snake.dx;
snake.y += snake.dy;
if ((snake.x < 0) || (snake.x >= canvas.width)) {
resetGame();
return;
}
if ((snake.y < 0) || (snake.y >= canvas.height)) {
resetGame();
return;
}
// keep track of where snake has been. front of the array is always the head
snake.cells.unshift({x: snake.x, y: snake.y});
// remove cells as we move away from them
if (snake.cells.length > snake.maxCells) {
snake.cells.pop();
}
// draw apple
context.fillStyle = 'red';
context.fillRect(apple.x, apple.y, grid-1, grid-1);
// draw snake one cell at a time
context.fillStyle = 'green';
snake.cells.forEach(function(cell, index) {
// drawing 1 px smaller than the grid creates a grid effect in the snake body so you can see how long it is
context.fillRect(cell.x, cell.y, grid-1, grid-1);
// snake ate apple
if (cell.x === apple.x && cell.y === apple.y) {
snake.maxCells++;
// canvas is 400x400 which is 25x25 grids
apple.x = getRandomInt(0, 25) * grid;
apple.y = getRandomInt(0, 25) * grid;
score ++;
bestscore = Math.max(bestscore, score);
showBestScore(bestscore);
showScore(score);
}
// check collision with all cells after this one (modified bubble sort)
for (var i = index + 1; i < snake.cells.length; i += 1) {
// snake occupies same space as a body part. reset game
if (cell.x === snake.cells[i].x && cell.y === snake.cells[i].y) {
resetGame();
return;
}
}
});
}If you allow snake to rewind to other side of the canvas, you can use the following code when checking the boundaries.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // wrap snake position horizontally on edge of screen if (snake.x < 0) { snake.x = canvas.width - grid; } else if (snake.x >= canvas.width) { snake.x = 0; } // wrap snake position vertically on edge of screen if (snake.y < 0) { snake.y = canvas.height - grid; } else if (snake.y >= canvas.height) { snake.y = 0; } |
// wrap snake position horizontally on edge of screen
if (snake.x < 0) {
snake.x = canvas.width - grid;
}
else if (snake.x >= canvas.width) {
snake.x = 0;
}
// wrap snake position vertically on edge of screen
if (snake.y < 0) {
snake.y = canvas.height - grid;
}
else if (snake.y >= canvas.height) {
snake.y = 0;
}The simple snake game can be played here: https://helloacm.com/static/game/snake/
Play Snake Game
Want to play the snake game? Here are two good options:
- Simple Snake Game in Javascript
- Chrome Extension: Snake Game
–EOF (The Ultimate Computing & Technology Blog) —
推荐阅读:8 Best WordPress Membership Plugins 6 Tips For Doing Taxes as a Freelancer 10 Tips on Recording Video Like a Pro With Your Smartphone Common Mistakes You Make Before Uploading a WordPress Blog Post How to Leverage Expert Roundups to Earn High-Quality Links For Y What Is Color Theory and Why Bloggers Should Know the Basics 5 Ways to Make Sure You Get Paid as an Online Freelancer Creating a Social Media Contest Strategy to Boost Engagement A Productivity & Health Guide for Home-Based Entrepreneurs Recursive Depth First Search Algorithm to Delete Leaves With a G
- 评论列表
-
- 添加评论