前言
万年无更,突然想起来还有这个,分享一下
功能说明
仿照以前game boy的贪吃蛇游戏
先选择速度及地图大小,点击[play]开始
[上][下][左][右]控制移动.[Space]暂停
吃掉食物得分,碰撞身体及地图边缘则结束
页面主要包含两个对象
1.配置及分数显示区域
2.地图(含贪吃蛇主体+食物对象)
设计上比较关键的几个方法,在代码中有简单注释
1.地图生成及贪吃蛇对象初始化,速度控制等
2.贪吃蛇控制方法
3.食物生成算法
4.设计贪吃蛇队列,计算长度及位置
5.积分计算
6.碰撞方法(吃食物or碰撞自身or碰撞地图边缘)
详细代码
<html>
<style>
select {
width: 120px;
}
#table td {
width: 10px;
height: 10px;
/*margin: 1px;*/
background: #f7fff3;
}
#table td.snakeBody {
background: #000000;
}
#table td.food {
background: #ff0000;
}
#info td {
color: white;
background: #000000;
}
</style>
<body id="body">
<table id="info">
<tr>
<td>
<label>LEVEL:</label>
</td>
<td>
<select id="level">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
</select>
</td>
</tr>
<tr>
<td>
<label>Field:</label>
</td>
<td>
<select id="field">
<option value="20_20">min(20*20)</option>
<option value="50_50">normal(50*50)</option>
<option value="80_80">max(80*80)</option>
</select>
</td>
</tr>
<tr>
<td>
<label>Source:</label>
</td>
<td>
<p id="source">0</p>
</td>
</tr>
<tr>
<td colspan="2" style="text-align:center">
<button onclick="refresh()" style="width: 120px;">Play</button>
</td>
</tr>
</table>
</body>
<html>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script>
/**
* 指定背景和初始化操作
* @param w 宽(格字数)
* @param h 高(格字数)
* @param level 级别(格字数)
* @constructor
*/
function Field(w, h, level) {
//清除所有
$("#table").remove();
//默认宽20格
this.width = w ? w : 20;
//默认高20格
this.height = h ? h : 20;
//级别
this.level = level ? level : 1;
//贪吃蛇队列
this.snakeQueue;
//当前行进方向
this.aspect = "right";
//下一个行进方向
this.nextAspect = "right";
//蛇头坐标
this.snakeHead = {"x": 3, "y": 1};
//显示
this.show = function () {
//创建活动区域table
$("#body").append("<table id='table' style='border: #0C0C0C solid 1px'></table>");
var table = $("#table");
for (var i = 1; i <= this.height; i++) {
$(table).append("<tr id='tr_" + i + "'></tr>");
var tr = $("#tr_" + i);
for (var j = 1; j <= this.width; j++) {
$(tr).append("<td id='tr_" + i + "td_" + j + "' x='" + j + "' y='" + i + "'></td>");
$("#tr_" + i + "td_" + j);
}
$(table).append(tr);
}
//初始化蛇
this.initSnake();
//初始化第一个食物
this.food();
};
//初始化蛇
this.initSnake = function () {
this.snakeQueue = new SnakeQueue(null);
this.snakeQueue.push({"x": 1, "y": 1});
this.snakeQueue.push({"x": 2, "y": 1});
this.snakeQueue.push({"x": 3, "y": 1});
};
//判断移动后的坐标是否合法
this.check = function (position) {
var x = parseInt(position.x);
var y = parseInt(position.y);
//超出了边界
if (x < 1 || y < 1 || x > this.width || y > this.height) {
return false;
}
//碰撞了身体
if ($("#tr_" + y + "td_" + x).hasClass("snakeBody")) {
return false;
}
return true;
};
this.move = function (aspect) {
//暂停判断
if(stop) return;
//判断方向和原方向相反,则按原方向前进
if ((aspect == "up" && this.aspect == "down") ||
(aspect == "down" && this.aspect == "up") ||
(aspect == "left" && this.aspect == "right") ||
(aspect == "right" && this.aspect == "left")) {
//撤销下一方向,按原方向前进
this.nextAspect = this.aspect;
aspect=this.aspect;
}
//蛇头坐标
var x = parseInt(f.snakeHead.x);
var y = parseInt(f.snakeHead.y);
//新坐标
var position;
switch (aspect) {
case "up":
position = {"x": x, "y": y - 1};
break;
case "down":
position = {"x": x, "y": y + 1};
break;
case "right":
position = {"x": x + 1, "y": y};
break;
case "left":
position = {"x": x - 1, "y": y};
break;
}
//校验新坐标是否合法
if (!this.check(position)) {
over = true;
alert("YOU DIE!");
return;
}
//更新方向
this.aspect = aspect;
//更新头坐标
this.snakeHead = position;
//将新的坐标加入队列
this.snakeQueue.push(position);
//如果吃到食物,则长度+1,重新刷新食物节点
if($("td.food").attr("id")=="tr_"+position.y+"td_"+position.x){
$("td.food").removeClass("food");
this.food();
//得分+1
var source = parseInt($("#source")[0].innerText);
$("#source")[0].innerText=source+1;
}else{
//如果没有吃到食物,则需要从队列中减掉一个
this.snakeQueue.pop();
}
};
//刷新食物
this.food=function(){
//获取剩余空白节点
var emptyTd = $("#table td:not(.snakeBody)");
// 获取一个范围内的随机数
var random = parseInt(1 + (emptyTd.length) * (Math.random()));
//食物
var foodTd = emptyTd[random];
$(foodTd).addClass("food");
};
this.stop=function () {
stop=!stop;
}
}
/**
* 定义贪吃蛇队列
* @param {[Int]} size [队列大小]
*/
function SnakeQueue(size) {
var list = [];
//向队列中添加数据
this.push = function (data) {
if (data == null) {
return false;
}
//如果传递了size参数就设置了队列的大小
if (size != null && !isNaN(size)) {
if (list.length == size) {
this.pop();
}
}
list.unshift(data);
//新加入的节点,增加标志位和颜色
$("#tr_" + data.y + "td_" + data.x).addClass("snakeBody");
return true;
};
//从队列中取出数据
this.pop = function () {
var data = list.pop();
//移除节点的标志位和颜色
$("#tr_" + data.y + "td_" + data.x).removeClass("snakeBody");
return data;
};
//返回队列的大小
this.size = function () {
return list.length;
};
//返回队列的内容
this.queue = function () {
return list;
}
}
/**
* 初始化
*/
function refresh() {
over = false;
stop = false;
//获取活动区域大小
var area = $("#field").val().split("_");
var w = parseInt(area[0]);
var h = parseInt(area[1]);
//获取速度级别
var level = parseInt($("#level").val());
//重置区域
f = new Field(w, h, level);
f.show();
//重置计时器
clearInterval(timer);
timer = window.setInterval("if(!over&&!stop) f.move(f.nextAspect);", 1000/f.level);
//指定焦点
$("#table").focus();
}
//定义活动区域
var f;
//定义计时器
var timer;
//结束标志
var over = false;
//暂停标志
var stop=false;
//定时器,游戏未结束的情况下,每0.5s向下移动方块
var timer;
//键盘监听
document.onkeydown = function (e) {
if (over) return;
var e = window.event ? window.event : e;
switch (e.keyCode) {
case 38: //up
f.nextAspect ="up";//延时转向
//f.move("up");//立即转向
break;
case 40: //down
f.nextAspect ="down";//延时转向
//f.move("down");//立即转向
break;
case 37: //left
f.nextAspect ="left";//延时转向
//f.move("left");//立即转向
break;
case 39: //right
f.nextAspect ="right";//延时转向
//f.move("right");//立即转向
break;
case 32: //空格键暂停,开始
f.stop();
break;
}
}
</script>