一 效果图
二 代码
思路就不说了。一千个读者,有一千个哈姆雷特。同样一千个程序员,有一千种方式实现贪吃蛇。
只有两个文件:index.html和way1.js
index.html文件
贪吃蛇1.container{
width:400px;
height:400px;
margin:60px auto;
padding:0px 0px 0px 0px;
border:1px solid black;
}
.container table{
width:100%;
height:100%;
border:none;
outline:none;
}
way1.js
(function(){
/******面向过程*******/
//将所有的数据集中放在一个Object中好管理。
var data={
snake_body:[],//用一个二维数组来存储。目前还没有任何蛇身。
snake_tail_old:null,//旧的蛇尾。为什么要记录它呢?因为我不想每次移动都重新重绘一遍表格。浪费性能。所以要追踪蛇尾。
food_location:null, //用来存储食物的位置。一维数组,两个值。
dir:null,//反向。
tds:[],//所有的单元格。
empty_block:[],//空白格子坐标。true,该位置可用。false该位置不可用。
m:20,//行
n:20, //列
speed:1,
automode:false,//自动模式。
handmode:false, //手动模式。手动模式优先。
timeout:null
};
//工具方法、辅助方法。有可能是数据范围,也有可能是视图范围。尽可能的混乱。
var Utils={
setEmptyFlag:function(location,flag){//true可用。false不可用。
//默认情况下400个格子可用。
var x = location[0] , y =location[1];
data.empty_block[x][y] = flag;
},
//为了后期可扩展。这里再定义一个方法。
getFoodLocation:function(m,n){
//如果蛇身大于200个格子。为了提高效率。则从剩余的空表中随机抽选。
var rest = [];
for(var i=0;i
for(var j=0;j
if(data.empty_block[i][j]){
rest.push([i,j]);
}
}
}
var index = parseInt(Math.random()*rest.length);
return rest[index];
},
initpaint:function(){
//蛇身位置。
var x1 = data.snake_body[0][0], y1 = data.snake_body[0][1];
data.tds[x1][y1].style.backgroundColor = "red";
//食物的位置。
var x1 = data.food_location[0], y1 = data.food_location[1];
data.tds[x1][y1].style.backgroundColor = "blue";
},
speedUp:function(){
if(data.speed >= 38){
data.speed = 38;//2000-38*50
}else{
data.speed ++;
}
},
repaint:function(gainscores){
//为了提高性能。只需要重绘新蛇头。消除旧蛇尾即可。
var x1 = data.snake_body[0][0], y1 = data.snake_body[0][1];
data.tds[x1][y1].style.backgroundColor = "red";
if(gainscores){//如果得分重绘食物。蛇尾增加一块。刚好旧蛇尾不用清除。
//食物的位置。
var x1 = data.food_location[0], y1 = data.food_location[1];
data.tds[x1][y1].style.backgroundColor = "blue";
}else{//如果不得分。则清除旧蛇尾。
var x1 = data.snake_tail_old[0], y1 = data.snake_tail_old[1];
data.tds[x1][y1].style.backgroundColor = "";
}
},
checkDie:function(newheader){
var die = false;
data.snake_body.forEach(function(d,i){
if(d[0] == newheader[0] && newheader[1] ==d[1]){
die = true;
return;
}
});
return die;
}
};
//按顺序初始化调用
function init(){
initTable();
initSnake();
initFood();
Utils.initpaint( );
}
//1初始化表格
function initTable(){
var table = document.createElement("table");
for(var i=0;i
data.tds[i]=[];
data.empty_block[i] =[];
var tr = document.createElement("tr");
for(var j=0;j
var td = document.createElement("td");
tr.appendChild(td);
data.tds[i][j]=td;
data.empty_block[i][j] = true;
}
table.appendChild(tr);
}
document.getElementById("container1").appendChild(table);
}
//2 初始化蛇的位置。
function initSnake(){
var x = parseInt(Math.random()*data.m);
var y = parseInt(Math.random()*data.m);
var location =[x,y];
data.snake_body.push( location );
//蛇头占用了。
Utils.setEmptyFlag(location,false);
}
//3 初始化蛇的位置。
function initFood(){
var location = Utils.getFoodLocation(data.m,data.n);
data.food_location = location;
//食物占用了。
Utils.setEmptyFlag(location,false);
}
// 添加按键事件 往既定方向性移动一格。
document.body.οnkeydοwn=function(e){
var keycode;
if((keycode =e.keyCode) || (keycode=e.keyWhich)){
if(keycode>=37 && keycode<=40){
if(data.automode )return;
data.handmode = true;
switch (keycode) {
case 37: data.dir="left";break;
case 38: data.dir="up";break;
case 39: data.dir="right";break;
case 40: data.dir="down";break;
}
move();
//data.handmode = false;
}
data.handmode = false;
}
}
//自动移动
function autoMove(){
if(data.timeout!=null)clearTimeout(data.timeout);
data.timeout = setTimeout(autoMove, 2000-data.speed*50);
//如果方向不为空。并且为自动模式。
if(data.dir && data.handmode == false ){
data.automode = true;
move();
data.automode = false;
}
}
//移动
function move(){
var oldheader = data.snake_body[0];//旧的蛇头。
var newheader =oldheader.concat([]);//新的蛇头。
var gainscores = false;
switch (data.dir) {
case "left": data.dir="left";newheader[1]--;
if(newheader[1]< 0) newheader[1] = data.m-1;break;
case "up": data.dir="up";newheader[0]--;
if(newheader[0]<0) newheader[0] = data.n -1 ;break;
case "right":data.dir="right";newheader[1]++;
if(newheader[1]>=data.m) newheader[1] = 0;break;
case "down": data.dir="down";newheader[0]++;
if(newheader[0]>=data.n) newheader[0] = 0;break;
}
//1 死亡检测。蛇头咬住蛇尾才算死。穿墙不死。老子规定的。
if(Utils.checkDie(newheader) ){
alert("game over. reload again");
window.location.reload();
return;
}
//2 更新蛇头和可用空白位置。
data.snake_body.unshift(newheader);
Utils.setEmptyFlag(newheader, false);//蛇头的空格占用了。
//3 检测得分 在蛇尾增加一块。不移除蛇尾。就是增加一块。
if(newheader[0] == data.food_location[0] && newheader[1] == data.food_location[1] ){
Utils.setEmptyFlag(data.snake_tail_old, false);//蛇尾的空格被占用
gainscores = true;
initFood();//重新初始化食物位置。
Utils.speedUp();
}else{//如果不得分。
data.snake_tail_old = data.snake_body.pop();//移除蛇尾。保留蛇头,添加新蛇头。
Utils.setEmptyFlag(data.snake_tail_old, true);//蛇尾的空格被释放。
}
//4 重绘
Utils.repaint( gainscores );
}
init();
autoMove();
})();