迷宫游戏 -- canvas

<!DOCTYPE html>
<html lang="zh-CN">
<head>
	<meta charset="utf-8">
	<title>maze 迷宫算法</title>
	<style>
		body { margin: 0; overflow: hidden;}
		.center{text-align: center;}
		.title{
			margin: 0px;
			color: #776e65;
			text-shadow: 1px 2px 3px #8f7a66;
			font-size: 60px;
			display: inline-block;
		}
		#divTitle{
			display: inline-block;
			margin-bottom: 10px;
		}
		.button {
			font-weight: bold;
			letter-spacing: 3px;
			display: inline-block;
			padding: 10px 20px;
			font-size: 17px;
			cursor: pointer;
			text-align: center;   
			text-decoration: none;
			outline: none;
			color: #fff;
			background-color: #8f7a66;
			border: none;
			border-radius: 15px;
			box-shadow: 0 9px #999;
		}
		.button:active {
		  	background-color: #bbada0;
		  	box-shadow: 0 5px #666;
		  	transform: translateY(4px);
		}
		#game{
			position: relative;
		}
		#mapCanvas{
			/*position: relative;*/
		}
		#pointCanvas{
			position: absolute;
			z-index: 2;
		}
		.game {
		    display: none;
		    position: absolute;
		    top: 0;
		    right: 0;
		    bottom: 0;
		    left: 0;
		    background: rgba(238, 228, 218, 0.5);
		    z-index: 100;
		    text-align: center;
		    -webkit-animation: fade-in 800ms ease 1200ms;
		    -moz-animation: fade-in 800ms ease 1200ms;
		    animation: fade-in 800ms ease 1200ms;
		    -webkit-animation-fill-mode: both;
		    -moz-animation-fill-mode: both;
		    animation-fill-mode: both;
		}

		.game p{
			color: #776e65;
		    font-size: 100px;
		    font-weight: bold;
		    height: 60px;
		    line-height: 60px;
		    margin-top: 222px;
		}
	</style>
</head>
<body>
	<div class="center">
		<div id="divTitle">
			<h1 class="title">-</h1>
			<button class="button" type="button" onclick="BtnGameStart()">重新开始</button>
		</div>
	</div>


	<div id="game" class="center">
		<canvas id="pointCanvas" width="400" height="400">
			pointCanvas
		</canvas>
		<canvas id="mapCanvas" width="400" height="400">
			mapCanvas
		</canvas>
	</div>

	<div class="game" onclick="gameSuccess(1)">
		<p class="game-p" style="float: left;margin-left: 5%">恭喜</p>
		<p class="game-p" style="float: right;margin-right: 5%">过关</p>
	</div>

	<script type="text/javascript">
		// 创建地图
		function Create(){

			this.i = 0;
			this.div = ['divTitle','pointCanvas','mapCanvas'];	// div 地图 点
			this.entrance = [1,1];				// 入口
			this.annal = [];					// 记录
			this.mapSize = '';					// 最大
			this.num = '';						// 次数
			this.exportEntrance = '';			// 出口 - 入口
			this.width = '';					// 墙 - 路 宽度
			this.taste = 0;						// 趣味 -- 入口处 >= 2
			this.position = [];					// 当前位置
			this.mapcanvas = '';				// mapcanvas 对象
			this.pointCanvas = '';				// pointCanvas 对象
			this.mapcanvasObj = {
				shadowBlur : 1,
			}

			this.Init = function(e){
				this.position = [];
				// 设置 关卡数
				if(sessionStorage.checkpoint){
					let str = sessionStorage.checkpoint;
					str = JSON.parse(str);
					if(this.i < str.checkpoint){
						e += 2;
					}
					this.i = str.checkpoint;	
				}else{
					let checkpoint = {checkpoint:1};
					sessionStorage.checkpoint = JSON.stringify(checkpoint);
					this.i = 1;
				}
				if((e & 1) === 0){
					// 确定是奇数
					e++;
				}
				this.checkpoint = e;
				this.num = Math.pow(e - 2,2) - (e >> 1);
				// this.num = 2;

				this.mapSize = e - 1;
				this.map = new Array(e);
				for(let i = 0; i < e; i++){
					this.map[i] = new Array(e).fill(0);
				}
				this.annal.push(this.entrance);
				this.OpenGrid(this.entrance);
				this.Route();
				this.Draw();
				this.Position();
			}
			// 地图 路线 生成
			this.Route = function(){
				let list,i = 0,n = 2;
				while(i < this.num){
					list = this.annal[this.annal.length - 1];
					if(!list){
						i++;
						n = 2;
						this.annal.pop();
						continue;
					}
					list = this.ConnectedGrid(list,2);
					list = this.JudgeGrid(list);

					if(list.length > 1){
						list[0] = list[this.Random(0,list.length)];
					}else if(list.length == 0){
						this.annal.pop();
						i++;
						continue;
					}
					this.OpenGrid(list[0]);
					this.annal.push(list[0]);
					this.OpenConnectedGrid();
					i++;
				}
				this.ExportEntrance();
			}
			// 相连的格子 偶数 - 奇数 默认 奇数
			this.ConnectedGrid = function(arr,n = 2){
				let list = [];
					if(arr[0] > 1  * n){
						list.push([arr[0] - n,arr[1]]);
					}
					if(arr[0] < this.mapSize - n){
						list.push([arr[0] + n,arr[1]]);
					}
					if(arr[1] > 1 * n){
						list.push([arr[0] ,arr[1] - n]);
					}
					if(arr[1] < this.mapSize - n){
						list.push([arr[0] ,arr[1] + n]);
					}
				return list;
			}
			// 打通相连的格子
			this.OpenConnectedGrid = function(){
				if(this.annal.length > 1){
					let arr = [];
					arr[0] = this.annal[this.annal.length - 1];
					arr[1] = this.annal[this.annal.length - 2];
					let x = (arr[0][0] - arr[1][0]) > 0 ? arr[0][0] - 1 : (arr[0][0] - arr[1][0]) == 0 ? arr[0][0] : arr[0][0] + 1;
					let y = (arr[0][1] - arr[1][1]) > 0 ? arr[0][1] - 1 : (arr[0][1] - arr[1][1]) == 0 ? arr[0][1] : arr[0][1] + 1;
					this.OpenGrid([x,y]);
				}
			}
			// 判断格子
			this.JudgeGrid = function(arr,code = 0){
				let list = [], that = this;
				if(code !== 1){
					arr.forEach(function(item){
						if(that.map[item[0]][item[1]] !== 1 ){
							list.push(item);
						}
					});
				}else{
					arr.forEach(function(item){
						if(that.map[item[0]][item[1]] === 1 ){
							list.push(item);
						}
					});
				}
				return list;
			}
			// 打通格子
			this.OpenGrid = function(arr){
				this.map[arr[0]][arr[1]] = 1;
				this.i++;
			}
			// 出口 - 入口
			this.ExportEntrance = function(){
				let i,x,y,l,code = 1,list = [],n = Math.pow(this.mapSize - 1,2);
				list[0] = [[1,0],[0,1]];
				list[1] = [];
				// 为了游戏的乐趣 还是不搞全随机的出口 先右边->下面->上面->左边
				l = i = this.mapSize - 1;

				while(i >= 1 && n > 0){
					code ? (x = i,y = l) : (x = l,y = i);
					if(this.map[x][y] == 1){
						list[1].push([x,y]);
					}
					if(list[1].length > 2){
						break;
					}
					--i;
					n--;
					if(i == 0){
						i = l;
						code = code ? 0 : l = 1;
					}
				}

				for(i = 0; i < list.length; i++){
					list[i] = list[i][this.Random(0,list[i].length)];
				}

				x = list[1][0];
				y = list[1][1];
				list[1] = l != 1 ? code ? [x,y + 1] : [x + 1,y] : code ? [x,y - 1] : [x - 1,y];
				for(i = 0; i < list.length; i++){
					this.OpenGrid(list[i]);
				}
				this.exportEntrance = list;

				// 为了增加游戏的趣味性 出口 路线要 >= 2
				if(this.taste == 1){
					list = this.ConnectedGrid(this.entrance,1);
					list = this.JudgeGrid(list);
					this.OpenGrid(list[0]);
				}
			}
			// 随机
			 /*
			 * m 	最小值
			 * n 	最大值
			 */
			this.Random = function(m,n){
				return Math.floor(Math.random()*(m - n) + n);
			}
			// 绘制 地图
			this.Draw = function(){
				let w = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
				// let h = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
				let wh = (w >> 1) - (w >> 3);

				this.div.forEach(function(item){
					obj = document.getElementById(item);
					obj.width = wh;
					obj.height = obj.width;
				});

				w = wh / (this.mapSize + 1);
				this.width = w;
				let that = this;
				this.mapcanvas = obj.getContext('2d');

				this.map.forEach(function(item,x){
					item.forEach(function(val,y){
						if(val === 0){
							that.mapcanvas.fillRect(y * w,x * w ,w,w);
						}
					});
				});
			}
			// 绘制 位置
			this.Position = function(code = 1,n = 1){
				if(this.position.length > 0){
					let list = [];
					list[0] = code ? this.position[0] : this.position[0] + n;
					list[1] = code ? this.position[1] + n : this.position[1];
					if(list[0] == this.exportEntrance[0][0] && list[1] == this.exportEntrance[0][1]){
						console.log('想越狱???');
						return;
					}
					if(list[0] == this.exportEntrance[1][0] && list[1] == this.exportEntrance[1][1]){
						gameSuccess();
						return;
					}
					list = this.JudgeGrid([list],1);
					if(list.length <= 0){
						return;
					}else{
						this.pointCanvas.clearRect(this.position[1] * this.width-1,this.position[0] * this.width-1,this.width+2,this.width+2);
						this.map[this.position[0]][this.position[1]] = 1;
						this.pointCanvas.beginPath();
						this.pointCanvas.arc(list[0][1]* this.width + this.width/2,list[0][0]* this.width + this.width/2,this.width - Math.round(this.width / 2),0,2*Math.PI);
						this.pointCanvas.stroke();
						this.pointCanvas.fill();
						this.position = [list[0][0],list[0][1]];
						this.map[this.position[0]][this.position[1]] = 2;
					}
				}else{
					let obj = document.getElementById('pointCanvas');
					this.pointCanvas = obj.getContext('2d');
					this.pointCanvas.beginPath();
					this.pointCanvas.arc(1* this.width + this.width/2,1* this.width + this.width/2,this.width - Math.round(this.width / 2),0,2*Math.PI);
					this.pointCanvas.stroke();
					this.pointCanvas.fillStyle = 'red';
					this.pointCanvas.fill();
					this.position = [1,1];
					this.map[1][1] = 2;
				}
			}
		};

		var maze = new Create();
		maze.Init(10);

		function BtnGameStart(){
			maze.Init(10);
			let str = sessionStorage.checkpoint;
			str = JSON.parse(str);
			str.checkpoint = 1;
			sessionStorage.checkpoint = JSON.stringify(str);
		}
		// game 过关成功
		function gameSuccess(code = 0){
			if(code){
				document.getElementsByClassName("game")[0].style.display = "none";
				maze.Init(maze.checkpoint);
			}else{
				document.getElementsByClassName("game")[0].style.display = "block";
				console.log('越狱成功!!!');
				let str = sessionStorage.checkpoint;
				str = JSON.parse(str);
				str.checkpoint++;
				sessionStorage.checkpoint = JSON.stringify(str);
			}
		}

		document.addEventListener("keydown", function (event) {
			switch(event.keyCode){
				case 37:
				case 65:
					//console.log('left'); 
					maze.Position(1,-1);				
					break;
				case 38:
				case 87:
					//console.log('top'); 
					maze.Position(0,-1);
					break;
				case 39:
				case 68:
					//console.log('right');
					maze.Position(1,1);
					break;
				case 40:
				case 83:
					//console.log('bottom');
					maze.Position(0,1);
					break;
				default:
					break;
			}
		});
	</script>

</body>
</html>

地图不应该是一个个小格子来的,渲染地图的时候可以根据地图数据来把相连的几个点的数据一起记录,x-x1 或 y-y1的。渲染地图时就可以直接使用,就不是一个个的渲染了。

定位 由于我是固定一个出入点 坐标(1,1);所以我是从这开始打洞,在该点上再次确认一个点,点与点之间要相隔一个点位,确认第二个点就打通它们之间的点位,避免一些死路出现。只要两点之间打通即可。按照这个思路即可创建地图。但是执行时间

5353 的地图 – 43.139892578125ms
103
103的地图 – 158.218994140625ms
153153的地图 – 176.302001953125ms
203
203的地图 – 190.451171875ms
好像有点慢 要优化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值