最近看到一篇博客,也是制作迷宫的,我仔细看了一下,里面涉及一个算法--并查集(不相交集合),没有听过,就打算练习一下,由于最近又在使用LayaAir,就打算用它来写。
我使用的是LayaAir2.2.0beta4
效果图:
1、创建工程,新建场景
新建一个脚本,脚本继承Laya.Script,把该脚本添加到场景里
2、画地图、画蓝色方块、红色方块
//画地图
this.m_lineBox = new Laya.Sprite();
this.setPos(this.m_lineBox,0,0);
this.setzOrder(this.m_lineBox,0);
this.owner.addChild(this.m_lineBox);
for (let i = 0; i < 16; i++) {
this.m_lineBox.graphics.drawLine(100,100+30*i,550,100+30*i,"#ffffff",2);
this.m_lineBox.graphics.drawLine(100+30*i,100,100+30*i,550,"#ffffff",2);
}
//画蓝色方块
this.m_blue = new Laya.Sprite();
this.m_blue.size(20,20);
this.setPos(this.m_blue,105,105);
this.setzOrder(this.m_blue,1);
this.owner.addChild(this.m_blue);
this.m_blue.graphics.drawRect(0,0,20,20,"#003dff","#003dff",1);
//画红色色方块
this.m_red = new Laya.Sprite();
this.m_red.size(20,20);
this.setPos(this.m_red,105+420,105+420);
this.setzOrder(this.m_red,0);
this.owner.addChild(this.m_red);
this.m_red.graphics.drawRect(0,0,20,20,"#ff0400","#ff0400",1);
//设置位置
private setPos(object:Laya.Sprite,x:number,y:number):void{
object.pos(x,y);
}
//设置层级
private setzOrder(object:Laya.Sprite,value:number):void{
object.zOrder = value;
}
3、移动蓝色方块
//键盘控制
onKeyDown(e:Laya.Event){
//蓝色方块移动
switch (e.keyCode) {
case 37:
this.moveObject(this.m_blue,-30,0);
break;
case 38:
this.moveObject(this.m_blue,0,-30);
break;
case 39:
this.moveObject(this.m_blue,30,0);
break;
case 40:
this.moveObject(this.m_blue,0,30);
break;
}
}
//移动对象
private moveObject(object:Laya.Sprite,x:number,y:number):void{
//判断能否移动
if(this.judgeMove(object,x,y)){
let toX = object.x+x;
let toY = object.y+y;
this.setPos(object,toX,toY);
//判断是否到达终点--于红色方块重合
if(this.m_blue.x==this.m_red.x&&this.m_blue.y==this.m_red.y){
console.log("过关了!");
//初始化蓝色方块
this.setPos(this.m_blue,105,105);
//清理地图
this.m_lineBox.graphics.clear();
//重画地图
for (let i = 0; i < 16; i++) {
this.m_lineBox.graphics.drawLine(100,100+30*i,550,100+30*i,"#ffffff",2);
this.m_lineBox.graphics.drawLine(100+30*i,100,100+30*i,550,"#ffffff",2);
}
//初始化节点数组
this.m_mapInfoAry.forEach(e => {
e.value = -1;
e.parent = null;
e.up = false;
e.down = false;
e.left = false;
e.right = false;
});
//初始化起始点、终止点
this.m_begin = new Laya.Point(this.m_blue.x-105,this.m_blue.y-105);
this.m_end = new Laya.Point(this.m_red.x-105,this.m_red.y-105);
//创建迷宫
this.createMaze(this.m_begin,this.m_end);
}
}
}
//判断移动
private judgeMove(object:Laya.Sprite,valueX:number,valueY:number):boolean{
let toX:number = object.x+valueX;
let toY:number = object.y+valueY;
//判断是否出界
if(toX>=105&&toX<=525&&toY>=105&&toY<=525){
let nowX = Math.floor((object.x-105) / 30);
let nowY = Math.floor((object.y-105) / 30);
let nowNodeInfo = this.m_mapInfoAry[nowY*15+nowX];
//判断是否相通
if(valueX>0&&nowNodeInfo.right){
return true;
}
else if(valueX<0&&nowNodeInfo.left){
return true;
}
else if(valueY>0&&nowNodeInfo.down){
return true;
}
else if(valueY<0&&nowNodeInfo.up){
return true;
}
return false;
}else{
return false;
}
}
4、创建节点类,创建节点数组,初始化起始点、终止点
class NodeInfo{
public value:number;//孩子数
public parent:NodeInfo;//父亲
public up:boolean;//上面是否打通
public down:boolean;//下面是否打通
public left:boolean;//左面是否打通
public right:boolean;//右面是否打通
constructor(value:number){
this.value = value;
this.parent = null;
this.up = false;
this.down = false;
this.left = false;
this.right = false;
}
}
//初始化起始点、终止点
this.m_begin = new Laya.Point(this.m_blue.x-105,this.m_blue.y-105);
this.m_end = new Laya.Point(this.m_red.x-105,this.m_red.y-105);
//初始化节点数组
for (let i = 0; i < 225; i++) {
this.m_mapInfoAry.push(new NodeInfo(-1));
}
4、画迷宫(用到了并查集)
private createMaze(begin:Laya.Point,end:Laya.Point):void{
begin.x = Math.floor(begin.x / 30);
begin.y = Math.floor(begin.y / 30);
end.x = Math.floor(end.x / 30);
end.y = Math.floor(end.y / 30);
let beginNode:NodeInfo = this.m_mapInfoAry[begin.y*15+begin.x];
let endNode:NodeInfo = this.m_mapInfoAry[end.y*15+end.x];
while(true){
let R_Num = Tool.GetRandomInt(0,224);
let R_NodeInfo = this.m_mapInfoAry[R_Num];
let dAry:Array<number> = [];
if(R_Num%15>0&&this.limitABUnion(R_Num-1,R_NodeInfo)){
dAry.push(1);
}
if(R_Num%15<14&&this.limitABUnion(R_Num+1,R_NodeInfo)){
dAry.push(2);
}
if(Math.floor(R_Num/15)>0&&this.limitABUnion(R_Num-15,R_NodeInfo)){
dAry.push(3);
}
if(Math.floor(R_Num/15)<14&&this.limitABUnion(R_Num+15,R_NodeInfo)){
dAry.push(4);
}
if(dAry.length!=0){
let dValue = Tool.GetRandomInt(0,dAry.length-1);
let tempNode:NodeInfo;
switch (dAry[dValue]) {
case 1:
tempNode = this.m_mapInfoAry[R_Num-1];
R_NodeInfo.left = true;
tempNode.right = true;
break;
case 2:
tempNode = this.m_mapInfoAry[R_Num+1];
R_NodeInfo.right = true;
tempNode.left = true;
break;
case 3:
tempNode = this.m_mapInfoAry[R_Num-15];
R_NodeInfo.up = true;
tempNode.down = true;
break;
case 4:
tempNode = this.m_mapInfoAry[R_Num+15];
R_NodeInfo.down = true;
tempNode.up = true;
break;
}
this.mopLine(R_Num%15*30+100,Math.floor(R_Num/15)*30+100,dAry[dValue]);
this.willABUnion(R_NodeInfo,tempNode,null);
if(this.judgeABUnion(beginNode, endNode))break;
}
}
}
//擦线
private mopLine(x:number,y:number,value:number){
switch (value) {
case 1:
this.m_lineBox.graphics.drawLine(x,y,x,y+30,"#000000",2);
break;
case 2:
this.m_lineBox.graphics.drawLine(x+30,y,x+30,y+30,"#000000",2);
break;
case 3:
this.m_lineBox.graphics.drawLine(x,y,x+30,y,"#000000",2);
break;
case 4:
this.m_lineBox.graphics.drawLine(x,y+30,x+30,y+30,"#000000",2);
break;
}
}
//限制AB联盟
private limitABUnion(Aindex:number,_B:NodeInfo):boolean{
let A = this.m_mapInfoAry[Aindex];
let B = _B;
if(!this.judgeABUnion(A,B))return true;
else return false;
}
//将AB联盟
private willABUnion(A:NodeInfo,B:NodeInfo,C:NodeInfo):void{
if(A.parent!=null){
if(B.parent!=null){
this.willABUnion(A.parent,B.parent,B);
}else{
this.willABUnion(A.parent,B,B);
}
}else{
if(B.parent!=null){
this.willABUnion(A,B.parent,B);
}else{
if(A.value==B.value){
A.parent = B;
B.value += A.value;
}else{
if(A.value<B.value){
B.parent = A;
A.value += B.value;
}else{
A.parent = B;
B.value += A.value;
}
}
}
}
}
//判断AB联盟
private judgeABUnion(A:NodeInfo,B:NodeInfo):boolean{
if(A.parent!=null){
if(B.parent!=null){
return this.judgeABUnion(A.parent,B.parent);
}else{
return this.judgeABUnion(A.parent,B);
}
}else{
if(B.parent!=null){
return this.judgeABUnion(A,B.parent);
}else{
if(A==B)return true;
else return false;
}
}
}
//随机数
public static GetRandomInt(min: number, max: number): number
{
var Gap = max - min;
var Rand = Math.random();
return(min + Math.round(Rand * Gap));
}