贪食蛇游戏很有趣, 而且也不复杂, 是学习一门编程语言的最好的入门练手的项目. 我在加入GE后接触到GE开发的Magik语言(Wiki), 便很快的用它写了一个贪吃蛇的游戏.
今天, 我们就来用当今最火的语言 Javascript 来写一下, 你就会发现, 其实这个游戏很简单就能实现了.
画板
我们需要一个游戏场景, 也就是画板 Canvas, 画板上我们需要每次清空, 然后画上蛇和苹果.
1 | <canvas width="400" height="400" id="game"></canvas> |
<canvas width="400" height="400" id="game"></canvas>
然后, 我们需要定义几个全局变量:
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, // 方向偏移量 dx: grid, dy: 0, // 蛇的身体坐标 cells: [], // 蛇的最小长度 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, // 方向偏移量 dx: grid, dy: 0, // 蛇的身体坐标 cells: [], // 蛇的最小长度 maxCells: 4 }; var apple = { x: 320, y: 320 };
游戏控制
在HTML页面加载完后, 我们可以通过事件 body.onload 来加载一个 windowload 函数.
1 | <body onload="windowload()"> |
<body onload="windowload()">
在这个函数里, 我们需要定义对蛇的控制, 也就是四个方向键. 当蛇往右的行走的时候, 方向左右键是没有效果的, 同样的, 当蛇往上行走的时候, 方向上下键是没有效果的, 这样避免了贪吃蛇马上吃到自己就狗带了.
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'); // 按键事件 document.addEventListener('keydown', function(e) { // 左 if (e.which === 37 && snake.dx === 0) { snake.dx = -grid; snake.dy = 0; } // 上 else if (e.which === 38 && snake.dy === 0) { snake.dy = -grid; snake.dx = 0; } // 右 else if (e.which === 39 && snake.dx === 0) { snake.dx = grid; snake.dy = 0; } // 下 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'); // 按键事件 document.addEventListener('keydown', function(e) { // 左 if (e.which === 37 && snake.dx === 0) { snake.dx = -grid; snake.dy = 0; } // 上 else if (e.which === 38 && snake.dy === 0) { snake.dy = -grid; snake.dx = 0; } // 右 else if (e.which === 39 && snake.dx === 0) { snake.dx = grid; snake.dy = 0; } // 下 else if (e.which === 40 && snake.dy === 0) { snake.dy = grid; snake.dx = 0; } }); window.requestAnimationFrame(loop); }
在函数的最后我们调用了 window.requestAnimationFrame函数. 这个函数需要一个回调函数. 让画板在重画的时候会调用它.
我们需要几个用到的 helper 函数.
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 | // 返回一个在 [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; } // 重置游戏 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; } |
// 返回一个在 [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; } // 重置游戏 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; }
主游戏循环
在游戏循环中, 我们需要递归地调用 requestAnimationFrame. 然后, 清除画布并绘制蛇的身体碎片和苹果. 如果蛇撞到墙壁或与身体碰撞, 则需要触发游戏结束. 当它移动时, 我们可以从它的尾部弹出一个坐标并将其插入到数组前面(头部).
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); // 缓慢游戏循环速度到15 fps = 60/4 if (++count < 4) { return; } count = 0; context.clearRect(0,0,canvas.width,canvas.height); // 蛇的位置移到下一格 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; } // 把新位置加到头部 snake.cells.unshift({x: snake.x, y: snake.y}); // 如果大于 maxCells, 我们就把尾巴去掉一个 if (snake.cells.length > snake.maxCells) { snake.cells.pop(); } // 画苹果 context.fillStyle = 'red'; context.fillRect(apple.x, apple.y, grid-1, grid-1); // 每次画一个绿色的身体 context.fillStyle = 'green'; snake.cells.forEach(function(cell, index) { // 绘制比网格小1像素的像素会在蛇体内创建网格效果, 因此您可以看到它有多长 context.fillRect(cell.x, cell.y, grid-1, grid-1); // 吃了苹果 if (cell.x === apple.x && cell.y === apple.y) { snake.maxCells++; // 画板 400x400 也就是 25x25 格 apple.x = getRandomInt(0, 25) * grid; apple.y = getRandomInt(0, 25) * grid; score ++; bestscore = Math.max(bestscore, score); showBestScore(bestscore); showScore(score); } // 是否和身体碰撞了 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); // 缓慢游戏循环速度到15 fps = 60/4 if (++count < 4) { return; } count = 0; context.clearRect(0,0,canvas.width,canvas.height); // 蛇的位置移到下一格 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; } // 把新位置加到头部 snake.cells.unshift({x: snake.x, y: snake.y}); // 如果大于 maxCells, 我们就把尾巴去掉一个 if (snake.cells.length > snake.maxCells) { snake.cells.pop(); } // 画苹果 context.fillStyle = 'red'; context.fillRect(apple.x, apple.y, grid-1, grid-1); // 每次画一个绿色的身体 context.fillStyle = 'green'; snake.cells.forEach(function(cell, index) { // 绘制比网格小1像素的像素会在蛇体内创建网格效果, 因此您可以看到它有多长 context.fillRect(cell.x, cell.y, grid-1, grid-1); // 吃了苹果 if (cell.x === apple.x && cell.y === apple.y) { snake.maxCells++; // 画板 400x400 也就是 25x25 格 apple.x = getRandomInt(0, 25) * grid; apple.y = getRandomInt(0, 25) * grid; score ++; bestscore = Math.max(bestscore, score); showBestScore(bestscore); showScore(score); } // 是否和身体碰撞了 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; } } }); }
如果蛇可以从屏幕的一边穿越到另一边, 你则需要使用下面的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // 水平穿越 if (snake.x < 0) { snake.x = canvas.width - grid; } else if (snake.x >= canvas.width) { snake.x = 0; } // 垂直穿越 if (snake.y < 0) { snake.y = canvas.height - grid; } else if (snake.y >= canvas.height) { snake.y = 0; } |
// 水平穿越 if (snake.x < 0) { snake.x = canvas.width - grid; } else if (snake.x >= canvas.width) { snake.x = 0; } // 垂直穿越 if (snake.y < 0) { snake.y = canvas.height - grid; } else if (snake.y >= canvas.height) { snake.y = 0; }
在线玩贪吃蛇游戏: https://helloacm.com/static/game/snake/
想立马玩贪吃蛇游戏?
英文: How to Make a Simple Snake Game in Javascript?
GD Star Rating
loading...
本文一共 631 个汉字, 你数一下对不对.loading...
上一篇: 英国 stagecoach 表演课真是又贵又费时的课外兴趣班啊
下一篇: Microbit 游戏编程: 贪心算法也无法让贪吃蛇永生
扫描二维码,分享本文到微信朋友圈