javascript贪吃蛇一(面向过程实现)

一 效果图

二 代码

思路就不说了。一千个读者,有一千个哈姆雷特。同样一千个程序员,有一千种方式实现贪吃蛇。

只有两个文件:index.html和way1.js

index.html文件

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>贪吃蛇1</title>
<style type="text/css">
.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;
	
}

</style>
</head>
<body>
<!-- 阶段1 完全面向过程 -->
<div class="container" id="container1"  ></div>
<script type="text/javascript" src="way1.js"></script>
</body>
</html>

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<m;i++){
				for(var j=0;j<n;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.m; i++){
			data.tds[i]=[];
			data.empty_block[i] =[];
			var tr = document.createElement("tr");
			for(var j=0;j<data.n;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.onkeydown=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();
})();

猜你喜欢

转载自my.oschina.net/lightled/blog/1825448