简单的 JavaScript 贪吃蛇基本原理

贪吃蛇的种类很多,今天我们说的这种是由很多格子组成的。

我的要求是尽可能的简单高效。

贪吃蛇一直困扰我的是转向之后为什么后面的方块会跟着前面的方块,有人说用数组把蛇的身体存储起来,道理我都懂,但是这是个什么原理呢?

首先我们先了解一下这个游戏的地图组成:

<div id="map">
    <div class="cellDiv"></div>
    <div class="cellDiv"></div>
    <div class="cellDiv"></div>
    <!--后面的div是相同的,此处省略-->
</div>

然后用css调整一下样式

*{ margin:0; padding: 0;}
#map{margin: 40px auto;border: 1px solid #000;}
.cellDiv{border: 1px solid #000;float: left; box-sizing: border-box;}

其中box-sizing: border-box;是css3,它可以压缩内边距,不会因为边框的大小影响样式。

地图创建好就是下图的样子,每个<div class="cellDiv"></div>都有一个编号,我们可以通过这个编号控制每一个div的样式,但是因为没有使用二维数组所以需要一个公式来进行转换,如22号div的位置,写成二位数组的形式就是arr[2][1],每一行有20个div,然而22=1*20+2,写成更一般的形式就是arr[x][y]=y*20+x;有了这个公式我们就可以通过加减x、y来控制蛇了。

下面是完整代码

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<style>
	*{ margin:0; padding: 0;}
	#map{margin: 40px auto;border: 1px solid #000;}
	.cellDiv{border: 1px solid #000;float: left; box-sizing: border-box;text-align: center;font-size: 12px;line-height: 24px;}
	.snakeCell{background-color: #f00;}
	.snakeFoodCell{background-color: #f0f;}
</style>
</head>

<body>

<div id="map"></div>

<script>

	var row=22;//行数
	var col=20;//列数
	var cellWidth=25;//单元格宽度
	var cellHeight=25;//单元格高度
	var Map=document.getElementById("map");
	Map.style.width=cellWidth*col+'px';
	Map.style.height=cellHeight*row+'px';
	
	function CreateMap(){//创建地图
		for(var i=0;i<row*col;i++){
			var cellDiv=document.createElement("div");
			cellDiv.className="cellDiv";
			cellDiv.innerText=i;
			cellDiv.style.width=cellWidth+'px';
			cellDiv.style.height=cellHeight+'px';
			Map.appendChild(cellDiv);
		}
	}
	
	CreateMap();
	
	
	var x=7;//蛇头初始x坐标
	var y=9;//蛇头初始y坐标
	var snakeLength=3;//蛇初始长度
	var snake=[];//存储蛇身
	for(var i=0,st=y*col+x;i<snakeLength;i++,st--){
		Map.getElementsByTagName("div")[st].className="cellDiv snakeCell";
		snake.push(st);
	}
	
	
	function eachSnake(){
		
		if(x<0 || x>col-1 || y<0 || y>row-1){//碰壁
			alert("Game Over");
			clearInterval(timerq);
			return;
		}
		
		var st=y*col+x;
		
		if(snake.slice(1).includes(st)){//吃到自己
			alert("Game Over");
			clearInterval(timerq);
			return;
		}
		
		if(st==snakeFoodId){//吃到食物
			snakeLength++;
			snake.unshift(st);
			createFood();
		}else{//没有吃到食物
			snake.unshift(st);
			var sw=snake.pop();
			//console.log(snake);
			Map.getElementsByTagName("div")[sw].className="cellDiv";
		}
		Map.getElementsByTagName("div")[st].className="cellDiv snakeCell";	
	}
	
	
	var vector="right";//初始方向
	var timerq;
	function snakeMove(){
		
		switch(vector){
			case 'right':
				x++;			
				break;
			case 'left':
				x--;			
				break;
			case 'up':
				y--;			
				break;	
			case 'down':
				y++;			
				break;
		}	
		eachSnake();
               pd=false;	}
	timerq=setInterval(snakeMove,140);
	
	var pd=false;
	document.onkeydown=function(event){
		
		if(pd){
			return;
		}
		
		var keyCode=event.keyCode;
		
		if((vector=='left' && keyCode==39) || (vector=='right' && keyCode==37) || (vector=='up' && keyCode==40) || (vector=='down' && keyCode==38)){
			return;
		}
		
		switch(keyCode){
			case 37:
				vector='left';
				break;
			case 38:
				vector='up';
				break;
			case 39:
				vector='right';
				break;
			case 40:
				vector='down';
				break;
		}
		pd=true;
		
	}
	
	var snakeFoodId;
	
	function createFood(){
		snakeFoodId=Math.round(Math.random()*(row*col-1));//食物位置
		if(snake.includes(snakeFoodId)){
			//alert("食物被创建到了蛇身上");
			createFood();
		}
		Map.getElementsByTagName("div")[snakeFoodId].className="cellDiv snakeFoodCell";
	}
	
	createFood();
	
</script>

</body>
</html>

这个贪吃蛇有一个问题就是,键盘快速连续按下的时候会有吃到自己,网络上大多数贪吃蛇代码都没有解决这个问题,这里使用pd=true;
setTimeout(function(){pd=false;},100);

来解决这个问题。但是这并不是最好的方法,当把蛇的速度设的很慢的时候,键盘快速连续按下时,依然有机会触发bug。

后来我想了一下,把setTimeout(function(){pd=false;},100);换了一个位置,完美解决了bug。

后来我又想了一下,根本不需要什么setTimeout,直接pd=false;就行了

今天我在IE上测试了一下,不能正常运行,edge可以,Chrome也可以。

猜你喜欢

转载自blog.csdn.net/n994298535/article/details/84451828