今天来做个吃水果上瘾的贪吃蛇游戏(大雾)

具体流程,就是先准备好要吃的食物,和蛇的构造(简单就好了。),以及游戏棋盘(我又不做 3D 的。)


    初始元素设置

代码:

    

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8"/>
		<style>
			table{border:1px solid #000;background:#000;}
			table tr>td{width:30px;height:30px;}
			table tr td{border:1px solid #777;box-sizing:border-box;}
			
			.food{width:30px;height:30px;border-radius:15px;background:#666;font-size:10px;line-height:30px;text-align:center;box-sizing:border-box;}
			.strawberry{background:pink;color:green;border:1px solid #faa;}
			.banana{background:yellow;color:#fa0;border:1px solid #fe0;}
			.grape{background:purple;color:#3ae;border:1px solid #a0a;}
			
			.div{height:30px;background:#000;padding-left:20px;}
			.div>div{float:left;width:30px;height:30px;}
			.head{background:#fff;opacity:0.8;}
			.body{background:#fff;opacity:0.5;}
			.tail{background:#fff;opacity:0.2;}
		</style>
	</head>
	<body>
		<ul>
			<li>
				<div class="food strawberry">草莓</div>
				<div class="food banana">香蕉</div>
				<div class="food grape">葡萄</div>
				<p>这是食物</p>
			</li>
			<li>
				<div class="div">
					<div class="head"></div>
					<div class="body"></div>
					<div class="body"></div>
					<div class="tail"></div>
				</div>
				<p>这是一条贪吃的幽灵蛇</p>
			</li>
		</ul>
		<table id="Checkerboard">					<!--	棋盘 -->
		</table>
	</body>
</html>
<script>
	function Checkerboard(obj = null){
		var $this = this;
		if(obj === null){
			obj = document.getElementById('Checkerboard');
		}
		$this.obj = obj;
		$this.xNum = 15;									//	定义 横 向数量
		$this.yNum = 15;									//	定义 纵 向数量
		$this.run = function(){								//	运行
			var html = '<tbody>';
			for(var i = 0;i < $this.yNum;i++){
				html += '<tr>';
				for(var ii = 0;ii < $this.xNum;ii++){
					html += '<td>';
				}
				html += '</tr>';
			}
			html += '</tbody>';
			$this.obj.innerHTML = html;						//	写入 html
		}
	}
	var obj = document.getElementById('Checkerboard');		//	对象目标
	var board = new Checkerboard(obj);
	board.run();											//	运行动作
</script>

    游戏开始准备

    接下来就是要把你的这条蛇初始放入游戏棋盘中了,这里将不设置开始键,等后续按钮设置好后,直接点击按钮直接开始游戏。

    代码:

//    算了,我懒了,所以一次性将代码放上来,然后再详细解说吧。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8"/>
		<style>
			table{border:1px solid #000;background:#000;}
			table tr>td{width:30px;height:30px;}
			table tr td{border:1px solid #777;box-sizing:border-box;}
			
			.food{width:30px;height:30px;border-radius:15px;background:#666;font-size:10px;line-height:30px;text-align:center;box-sizing:border-box;}
			.strawberry{background:#fcc;color:green;border:1px solid #faa;}
			.banana{background:#fe8;color:#fa0;border:1px solid #fe0;}
			.grape{background:#828;color:#3ae;border:1px solid #a0a;}
			
			.div{height:30px;background:#000;padding-left:20px;}
			.div>div{float:left;width:30px;height:30px;}
			.head{background:#fff;opacity:0.6;text-align:center;line-height:30px;}
			.body{background:#fff;opacity:0.3;}
			.tail{background:#fff;opacity:0.2;}
			.str{background:#fcc;}
			.ban{background:#fe8;}
			.gra{background:#828;}
		</style>
	</head>
	<body>
		<ul>
			<li>
				<div class="food strawberry">草莓</div>
				<div class="food banana">香蕉</div>
				<div class="food grape">葡萄</div>
				<p>这是食物</p>
			</li>
			<li>
				<div class="div">
					<div class="se head">蛇</div>
					<div class="se body"></div>
					<div class="se body"></div>
					<div class="se tail"></div>
				</div>
				<p>这是一条贪吃的幽灵蛇</p>
			</li>
		</ul>
		<table id="Checkerboard">					<!--	棋盘 -->
		</table>
	</body>
</html>
<script>
	function Checkerboard(obj = null){
		var $this = this;
		if(obj === null){
			obj = document.getElementById('Checkerboard');
		}
		$this.obj = obj;
		$this.xNum = 20;									//	定义 横 向数量
		$this.yNum = 20;									//	定义 纵 向数量
		$this.food = [['strawberry','草莓','str'],['banana','香蕉','ban'],['grape','葡萄','gra']];		//	食物类名
		$this.type = 2;										//	游戏模式,1 可以穿墙 2 不可以穿墙
		
		/**
			按钮定义
		**/
		var dict = {'a':65,'b':66,'c':67,'d':68,'e':69,"f":70,"g":71,"h":72,"i":73,"j":74,"k":75,"l":76,"m":77,"n":78,"o":79,"p":80,"q":81,"r":82,"s":83,"t":84,"u":85,"v":86,"w":87,"x":88,"y":89,"z":90,"up":38,"right":39,"left":37,"down":40};
		$this.up = 'up';
		$this.left = 'left';
		$this.right = 'right';
		$this.down = 'down';
		
		/**
			速度控制
		**/
		$this.maxSpeed = 10;								//	最快速度,最快不得低于每 10 毫秒移动一次
		maxSpeed = 10;
		$this.minSpeed = 160;								//	最慢速度不得高于每1秒移动一次
		minSpeed = 1000;
		
		state = true;										//	游戏状态 false 为结束
		
		valueOpition = [[0,0,'fff'],[0,1,'fff'],[0,2,'fff'],[0,3,'fff']];		//	初始化坐标
		var map = new Array,								//	地图
			newMap = null,									//	标识使用
			moveD = null,									//	蛇的移动方向
			moveED = null,									//	蛇的尾部方向,用于生成新的身板。
			foodOption,										//	食物位置
			objLength,										//	蛇的长度
			objOpsition = new Array;						//	蛇的位置信息
		
		$this.run = function(){								//	运行
			var html = '<tbody>';
			for(var i = 0;i < $this.yNum;i++){
				html += '<tr>';
				for(var ii = 0;ii < $this.xNum;ii++){
					html += '<td>';
				}
				html += '</tr>';
			}
			html += '</tbody>';
			$this.obj.innerHTML = html;						//	写入 html
			//	因为坐标将通过索引位置来进行查找,所以在这之前需要为每个元素添加对应的索引。
			//	索引初始化
			var tbody = $this.obj.childNodes;
			var tr = tbody[0].childNodes;
			for(var i = 0;i < tr.length;i++){
				var td = tr[i].childNodes;
				tr[i].index = i;
				for(var ii = 0;ii < td.length;ii++){
					td[ii].index = ii;
					map.push([ii,i]);
				}
			}
			
			//	数据初始化
			state = true;
			objLength = valueOpition.length;
			if($this.maxSpeed < maxSpeed)$this.maxSpeed = maxSpeed;
			if($this.minSpeed > minSpeed)$this.minSpeed = minSpeed;
			objOpsition = valueOpition;
			
			createObj(valueOpition);							//	生成蛇初始位置
			createFood(tr);										//	生成食物
			controller();										//	控制器
			move();
		}
		
		/**
			这是对蛇的操作部分
		**/
		
		//	按钮控制,让蛇动起来。
		//	修改蛇头移动方向,让下次运动的时候朝着对应方向前进
		var controller = function(){
			document.onkeydown = function(event){
				event = event || window.event;
				var code = event.keyCode;
				//	上 up
				var upCode = $this.up.toLowerCase();
				upCode = dict[upCode];
				//	下 down
				var downCode = $this.down.toLowerCase();
				downCode = dict[downCode];
				//	左 right
				var rightCode = $this.right.toLowerCase();
				rightCode = dict[rightCode];
				//	右 left
				var leftCode = $this.left.toLowerCase();
				leftCode = dict[leftCode];
				switch(true){
					case (code == upCode):
						if(moveD != 'down'){
							moveD = 'up';
						}
						break;
					case (code == downCode):
						if(moveD != 'up'){
							moveD = 'down';
						}
						break;
					case (code == rightCode):
						if(moveD != 'left'){
							moveD = 'right';
						}
						break;
					case code == leftCode:
						if(moveD != 'right'){
							moveD = 'left';
						}
						break;
					default:
				}
			}
		}
		
		var move = function(){									//	蛇的移动
			num = 10;											//	帧频时间设置
			
			//	速度计算
			var time = $this.minSpeed / (objLength - valueOpition.length + 1);
			if(time < $this.maxSpeed){
				time = $this.maxSpeed;
			}
			
			var timer = 0;
			//	运动执行
			var interval = setInterval(function(){
				if(moveD != null && timer > time){							//	有方向,证明游戏开始了。
					timer = 0;												//	重置计时器
					//	清空蛇身
					var obj = $this.obj.getElementsByClassName('se');
					var len = obj.length
					for(var i = 0;i < len;i++){
						obj[0].innerHTML = '';
						obj[0].classList = new Array;
					}
					
					
					//	重新生成
					objOpsition.pop();
					var x = objOpsition[0][0];
					var y = objOpsition[0][1];
					switch(moveD){
						case 'up':
							y--;
							break;
						case 'down':
							y++;
							break;
						case 'right':
							x++;
							break;
						case 'left':
							x--;
							break;
					}
					
					//	游戏模式检测
					switch($this.type){
						case 1:
							if(x < 0 || x >= $this.xNum || y < 0 || y >= $this.yNum){
								state = false;
							}
							break;
						case 2:
							if(x < 0){
								x = $this.xNum - 1;
							}else if(x >= $this.xNum){
								x = 0;
							}
							if(y < 0){
								y = $this.yNum - 1;
							}else if(y >= $this.yNum){
								y = 0;
							}
							break;
					}
					
					if(state){
						//	检测是否吃东西了没?
						tertingTakeFood(x,y);
						
						objOpsition.unshift([x,y,'fff']);
						var result = createObj(objOpsition);		//	创建蛇
						if(!result){
							over(interval);
						}
					}else{
						over(interval);
					}
				}
				timer += num;									//	时间叠加
			},num);
		}
		
		//	根据传入数据,解析坐标,然后生成对应的蛇~~~
		var createObj = function(optionArr){					//	在棋盘中创建蛇
		
			objOpsition = new Array;							//	重新编写位置信息。
			
			var tr = $this.obj.childNodes[0].childNodes;
			var jsonStr = JSON.stringify(optionArr);
			
			for(var i = 0;i < optionArr.length;i++){
				var x = optionArr[i][0];
				var y = optionArr[i][1];
				if(i >= optionArr.length - 1){
					var color = optionArr[i][2];
				}else{
					var color = optionArr[i + 1][2];
				}
				
				
				switch(true){
					case i == 0:
						//	蛇头 head
						
						//	检测是否咬到自身
						var str = JSON.stringify(optionArr[i]);
						var lstr = jsonStr.slice(jsonStr.lastIndexOf(str) + str.length);
						str = str.slice(0,str.lastIndexOf(',')) + ',';
						if( lstr.indexOf(str) != -1){
							return false;							//	咬到自己了,返回失败
						}
						
						tr[y].childNodes[x].classList.add('se','head',color);
						tr[y].childNodes[x].innerHTML = '蛇';
						break;
					case i > 0 && (i < optionArr.length - 1):
						//	蛇身 body
						tr[y].childNodes[x].classList.add('se','body',color);
						break;
					default:
						//	记录尾部方向,相对于前面那个,尾部在它的哪个方向
						var lx = optionArr[(i - 1)][0];
						var ly = optionArr[(i - 1)][1];
						switch(true){
							case lx > x:
								moveED = 'left';
								break;
							case lx < x:
								moveED = 'right';
								break;
							case ly > y:
								moveED = 'up';
								break;
							case ly < y:
								moveED = 'down';
								break;
						}
						//	蛇尾 tail
						tr[y].childNodes[x].classList.add('se','tail',color);
				}
				objOpsition.push([x,y,color]);
			}
			return true;
		}
		
		//	检测吃东西了没
		var tertingTakeFood = function(x,y){
			if(x == foodOption[0] && y == foodOption[1]){
				var len = objOpsition.length;
				var l = objOpsition[(len - 1)];						//	临时数据
				x = l[0];
				y = l[1];
				var color = l[2];
				objOpsition[(len - 1)][2] = foodOption[2];
				
				switch(moveED){
					case 'up':
						y--;
						break;
					case 'down':
						y++;
						break;
					case 'left':
						x--;
						break;
					case 'right':
						x++;
						break;
				}
				objOpsition.push([x,y,color]);
				$this.obj.getElementsByClassName('food')[0].innerHTML = '';
				$this.obj.getElementsByClassName('food')[0].classList = new Array();
				createFood();											//	重新生成食物
			}
		}
		
		
		/**
			这是对食物的操作部分
		**/
		var createFood = function(tr = null){						//	食物生成
			if(tr === null){
				tr = $this.obj.childNodes[0].childNodes;
			}
			var index = rand($this.food.length,0);					//	随机获取一个食物
			var food = $this.food[index];
			
			var CFoodOpsition = function(){							//	生成食物位置
				if(newMap === null){
					newMap = createNewMap();
				}
				var x = rand($this.xNum,0);
				var y = rand($this.yNum,0);
				
				if(newMap.indexOf('[' + x + ',' + y + ']') != -1){
					newMap = null;									//	更新标识
					return [x,y];
				}else{
					return CFoodOpsition();
				}
			}
			var opsition = CFoodOpsition();
			var x = opsition[0];
			var y = opsition[1];
			var obj = tr[y].childNodes[x];
			obj.classList.add('food',food[0]);
			obj.innerHTML = food[1];
			foodOption = [x,y,food[2]];										//	记录食物所在位置
		}
		
		var createNewMap = function(){								//	新的可用地图
			//	将地图 map 转换成 json 字符串,然后处理结束后,再进行转换。
			var jsonStr = JSON.stringify(map);						//	json 字符串
			var returnMap;
			for(var i = 0;i < objOpsition.length;i++){
				var x = objOpsition[i][0];
				var y = objOpsition[i][1];
				opsitionStr = '[' + x + ',' + y + ']';
				var index = jsonStr.indexOf(opsitionStr);
				var p = jsonStr.slice(0,index);
				var n = jsonStr.slice((index + opsitionStr.length)).replace(/^\,s*/g,"");
				jsonStr = p + n;
			}
			returnMap = jsonStr;
			return returnMap;
		};
		
		var rand = function(max = 10,min = 0){						//	随机数
			var num = 0;
			if(max > min){
				num = Math.floor(Math.random() * (max - min)) + min;
			}
			return num;
		};
		
		var over = function(interval){
			alert('GAME OVER!');
			$this.run();											//	重新开始
			clearInterval(interval);
			moveD = null;
		}
	}
	
	var obj = document.getElementById('Checkerboard');				//	对象目标
	var board = new Checkerboard(obj);
	board.run();													//	运行动作
</script>



    //    整个贪吃蛇逻辑,分为三个部分: 

        一、游戏初始设置。

                    游戏初始设置,包括棋盘的建立,蛇的初始位置设立,控制按钮的建立,食物的建立
                     棋盘建立,由对象的 xNum 属性决定每行有多少列,yNum 决定棋盘有多少列数。
                    蛇的初始位置设立通过对象内部的私有属性 valueOpition 定义好数组(本来想写方便些的,后来懒得写了),可以设立多组参数,每组参数依次记录 x 轴位置,y 位置,以及颜色类名设置(这个是因为有个朋友提出,吃掉一个食物后,生成一种对应颜色的身体,所以增加了第三个参数设置,可以根据自己需求修正过来。)。
                    按钮的建立,按钮对应的字典 (内部私有属性) dict ,我只写入了二十六个字母,和 上下左右按钮,其它的酌情修改。每个按钮都可以在外部通过对象的  up 、down 、 left 、right 属性修改对应的操作键,它们分别对应 上、下、左、右 。
                    食物的建立,在这里食物不是固定的,每次生成都会根据 对象属性 food 中的一个随机目标进行生成。可以提供多组数据,每组数据设立三个参数,分别是 食物样式类名,食物显示文字,以及蛇吃了后所改变颜色的样式名。
                    这上面的都是基本要素,当然,还根据我的需求情况我还设置了:
                    对象属性:
                            type : 游戏模式控制,1 : 不可穿墙 2:可穿墙
                            maxSpeed:最快速度,即贪吃蛇最快的移动速度,不会低于这个。
                            minSpeed:最慢速度,即贪吃蛇最慢的移动速度,不会高于这个。   
                    内部私有属性:
                            maxSpeed:内部限制最快速度,即对象属性的设置最小值只能是以这个为标准。
                            minSpeed:内部限制最慢速度,即对象的属性设置最大值只能是以这个为标准。
                            state:    游戏状态,当该状态为 false ,则游戏失败。
                            map,newMap:游戏地图,以及可用地图,用于生成食物时,避免与蛇身交错计算。
                            moveD,moveED:分别由于标识蛇头移动方向(在没有操作时,蛇将持续以这个方向移动),尾部对于前面的方向,用于生成新的身体部分时使用。
                            objLength:蛇的长度。
                            objOpsition:蛇的位置记录
                    方法:
                            对象方法:run 用于开始游戏的运行与初始化。

        二、蛇的运动控制

                蛇的运动,一需要不断的渲染,以及蛇的移动方向变更,最后的就是蛇的进食

                不断渲染,这样才能让蛇成为“移动的”,需要设置一个创建蛇身体的函数,根据传入的蛇位置信息,进行创建一个新的蛇。并且,设立一个不断在运行的方法,对蛇不断地更新,需要不断地删除它,然后依据新的位置重新生成,来达成移动的效果。并且如果你的设定是蛇不能咬自己的,还需要在生成蛇的时候进行判断,自己的头是否和身体的某个部分进行重合了。

                移动方向的控制:这里移动方向的控制,就需要根据设定好了的四个按钮,触发事件然后根据不同按钮,修改属性 moveD 来修改蛇移动的方向,最终让在不断渲染的方法,依据该属性,不断地修改蛇的位置信息,最后再生成新的蛇,这样看起来就是在不断前进了。

                蛇的进食:蛇的进食和是否咬身体的逻辑一样,检测头是否和食物进行重合,这里我的食物是用类名 food 作为标记的。在进食食物后,需要注意的一点是,要重新生成新的食物。

        三、食物的控制

                   食物的控制,其实也就只是食物的生成而已,需要注意的是,生成的食物,是不能和蛇的身体进行重合的,而且食物的位置是随机的,需要进行随机,并且判断是否在允许位置才能生成。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值