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
无此问题,无深究,估计是库的帧事件的实现方式的问题?)
演示
[在线演示]
[下载地址]
用户登录
还没有账号?
立即注册