HTML5《贪吃蛇》小游戏
游戏背景
贪吃蛇又名贪食蛇,是一款经典的小游戏。玩家使用方向键操控一条长长的蛇不断吞下豆子,
同时蛇身随着吞下的豆子不断变长,当蛇头撞到蛇身或障壁时游戏结束。
贪吃蛇最初为人们所知的是诺基亚手机附带的一个小游戏,它伴随着诺基亚手机走向世界。
现在的贪吃蛇出现了许多衍生版本,并被移植到各种平台上。
(以上为百度百科资料)
游戏规则
贪吃蛇的基本规则是控制一条不停走动的蛇,只能通过左、右2个方向90°转弯,在行走过程中通过吃豆子(食物)得分,如果撞上自己的身体或墙壁既游戏结束。还有一些衍生的版本有血槽、障碍物等丰富的内容,这些丰富的游戏要素在此次的版本中……都不涉及……
这次做的贪吃蛇的游戏规则设置的比较简单:
- 撞上墙壁游戏结束。 ( 也可以通过修改判断条件实现行走至墙壁会从对面墙壁穿越回来)
- 撞上自己身体游戏结束
- 每吃一个食物分数加1
运行截图

实现过程
游戏初始化
首先进行资源 (图片) 的加载,加载完毕后执行初始化函数 gameInit
imgData = new Array (
{name:"bg", path:"images/bg.png"},
{name:"btn", path:"images/btn.png"},
{name:"king", path:"images/king.jpg"}
)
//……略
var main = function() {
//填充背景
backLayer.graphics.drawRect(5,"#BD8D46",[0,0,option.canvasWidth,option.canvasHeight],true,"#E6E2AF");
addChild(backLayer);
loadingLayer = new LoadingSample1();
backLayer.addChild(loadingLayer);
//加载方法
LLoadManage.load(
imgData,
function(progress) {
loadingLayer.setProgress(progress);
},
function(result) {
imglist = result;
backLayer.removeChild(loadingLayer);
loadingLayer = null;
bgMapData[0] = new LBitmapData(imglist["bg"], 0, 0, option.imgStep, option.imgStep);
bgMapData[2] = new LBitmapData(imglist["bg"], option.imgStep, 0, option.imgStep, option.imgStep);
bgMapData[1] = new LBitmapData(imglist["bg"], option.imgStep*2, 0, option.imgStep, option.imgStep);
//游戏初始化
gameInit();
}
);
}
游戏初始化函数用于初始化各个游戏层以及层内元素
var gameInit = function() {
//初始化背景
initBackground();
//初始化控制按钮
initButton();
//初始化蛇
initSnake();
//初始化食物
initFood();
//初始化得分
initScore();
}
- 初始化背景:建立背景的地图小格子内容。
- 初始化控制按钮:建立按钮显示层,同时设置按钮事件。 (同时支持键盘方向键)
- 初始化蛇:建立蛇显示层,并通过调用 snakeLoop 方法实现刷新绘制蛇的行走动画。
snakeLoop 方法内包括行走判断、游戏结束判断等内容 - 初始化食物:建立食物显示层,随机显示一个食物于未被蛇身体占据的位置。
- 初始化得分:建立分数显示层,初始化分数显示。
蛇的行走
switch (goWay) {
case "top":
y = snake[snake.length-1].y-1;
if (y<1) {
if (!option.loopMap) gameover("撞到边界拉 ┑( ̄。 ̄)┍");
y = option.map.y;
}
snake.push({x:snake[snake.length-1].x, y:y});
break;
case "bottom":
y = snake[snake.length-1].y+1;
if (y>option.map.y) {
if (!option.loopMap) gameover("撞到边界拉 ┑( ̄。 ̄)┍");
y = 1;
}
snake.push({x:snake[snake.length-1].x, y:y});
break;
case "left":
x = snake[snake.length-1].x-1;
if (x<1) {
if (!option.loopMap) gameover("撞到边界拉 ┑( ̄。 ̄)┍");
x = option.map.x;
}
snake.push({x:x, y:snake[snake.length-1].y});
break;
case "right":
x = snake[snake.length-1].x+1;
if (x>option.map.x) {
if (!option.loopMap) gameover("撞到边界拉 ┑( ̄。 ̄)┍");
x = 1;
}
snake.push({x:x, y:snake[snake.length-1].y});
break;
}
通过 snakeLoop 函数判断当前行走方向变量 goWay , 按照前进方向,给蛇的身体数组 "snake" 头部增加一个方块(增加一个数组元素,为方块坐标),并在此判断是否撞到边界。
if (snake[snake.length-1].x==food.x && snake[snake.length-1].y==food.y){
if (snake.length>=(option.map.x*option.map.y)) {
option.godMode = false;
gameover("长度太长拉 ┑( ̄。 ̄)┍");
}
//与食物坐标重合,重新设置食物
setFood();
//设置分数
setScore();
} else if (snakeCache[(snake[snake.length-1].y-1)*option.map.x+(snake[snake.length-1].x)]==1) {
//碰到自己身体
gameover("撞到自己啦 ┑( ̄。 ̄)┍");
} else {
//普通移动,移除最末一个方块
snake.shift();
}
drawSnake();
若不是撞到边界,则进行判断:
- 如果和食物坐标重合,表示吃到食物,不移除尾部方块。(此处再加上判断是否超过地图最大容量)
- 如果和蛇的身体占用位置从何,表示撞到自己,执行gameover。
- 如果以上情况都不是,则是普通行走,从尾部移除一个方块。
判断完行走情况之后执行绘制函数 drawSnake ,在屏幕上绘制出蛇的形状。
最后给 snakeLoop 函数增加一个定时循环,就可以让蛇看起来在屏幕上“行走”了,通过控制定时时间则可以实现蛇的行走速度快慢的改变。
canTurn 变量在改变一次方向后会设为flase,表示不能再转向(连续多次改变转向),在行走过一步后,将 canTurn 变量设为true,表示可以进行转向,防止快速改变方向时行走错乱。
蛇的绘制
var drawSnake = function() {
var i, j;
snakeCache = new Array();
for (i=0, j=snake.length; i
遍历snake数组绘制蛇的形状,并同时更新蛇的占地位置 snakeCache。
地图空白位置
var getPos = function() {
var x, y;
//[1~地图宽度]随机数
while(true) {
x = Math.ceil(Math.random()*option.map.x);
y = Math.ceil(Math.random()*option.map.y);
if (!snakeCache[(y-1)*option.map.x + x]) break;
}
return {
x : x,
y : y
}
}| 1 | 2 | 3 | 4 |
| 5 | 6 | 7 | 8 |
| 9 | 10 | 11 | 12 |
| 13 | 14 | 15 | 16 |
snakeCache 数组用于存放蛇的占位信息,这里使用的方法是给地图中每个方块一次编上数字作为下标(类似上面的表格的形式),设置true、false,是否占用状态。
获取到空白位置后则可以实现给地图随机空白地方生成食物。
其他
- gameover 方法
- 分数计算
要点
- 通过
snakeCache变量实时存储被蛇占用的位置,确保食物生成的位置是未被占用的。 - 通过
canTurn变量,确保改变方向防止用户快速改变方向的时候行走错乱。 - 用 lufylegend 本身的帧事件实现行走动画的时候会有“延迟一步”的问题,手感上就是行走动作和按键之间有延迟。 (发现用
setInterval无此问题,无深究,估计是库的帧事件的实现方式的问题?)
演示
[在线演示]
[下载地址]
