A* +二叉堆 斜视45度寻路
前段时间在园子提问关于45度 没有找到好的解决方法
下面是自己写的A*,基于as3 3.0实现的 代码如有不妥和bug之处 大家请指正
贡献源代码这个是在我之前做一个flash的虚拟城市用到的
mapDataInfo 是地图的数据信息
没有经过优化 这两天有点浮躁天气热 了
/*
=================================================================================================
E_the code
2009/02/28 A* Astar Road 斜视45度
=================================================================================================
*/
package gamesrc.com{
import gamesrc.Model.mapDataInfo;
//import flash.utils.ByteArray;
//import flash.utils.getTimer;
public class SearchRoad {
private var endx:uint;
private var endy:uint;
private var openA:Array;
private var closeA:Array;
private var isfindpath:Boolean=false;
private var findA:Array;
//横或竖向移动一格的路径评分
private const COST_STRAIGHT : int = 10;
//斜向移动一格的路径评分
private const COST_DIAGONAL : int = 14;
private static var _getInstance:SearchRoad;
private var maxStep:int=1000;
private var mstep:int=0;
private var isuseOpenlist:Boolean;
//起点
//private var startX:uint;
//private var startY:uint;
public function SearchRoad()
{
}
public function searchRoads(sx:uint,sy:uint,endx:uint,endy:uint):Array
{
isfindpath=false;
var empArray:Array=null;
isuseOpenlist=false;
openA=new Array();
closeA=new Array();
mstep=0;
findA=mapDataInfo.mapArray;
this.endx=endx;
this.endy=endy;
//this.startX=sx;
//this.startY=sy;
openA.push([sx,sy,sx,sy,0,0]);//[sx,sy,px,py,g,f]
seachRoad();
if(isfindpath){
return getpath();
}
//trace(findA[endy][endx])
openlistHF();
iscloseHF();
return empArray;
}
private function iscloseHF():void
{
for each(var sA:Array in closeA)
{
findA[sA[1]][sA[0]]=0;
}
}
private function getpath():Array
{
var py:int=0;
var px:int=0;
var len:int=this.closeA.length-1;
var pathArray:Array=new Array();
//trace(this.closeA.length)
for(var pt:int=len;pt>=0;pt--)
{
//trace(this.closeA[pt])
if(pt==len)
{
px=this.closeA[pt][2];
py=this.closeA[pt][3];
pathArray.push([closeA[pt][0],closeA[pt][1]]);
}
else if(closeA[pt][1]==py&&closeA[pt][0]==px)
{
px=this.closeA[pt][2];
py=this.closeA[pt][3];
pathArray.push([closeA[pt][0],closeA[pt][1]]);
}
findA[closeA[pt][1]][closeA[pt][0]]=0;
}
openlistHF();
return pathArray.reverse();
}
//恢复开启列表的元素
private function openlistHF():void
{
for each(var sA:Array in openA)
{
findA[sA[1]][sA[0]]=0;
}
}
public function seachRoad():void
{
var tempOA:Array;
while(openA.length>0&& !isfindpath)
{
if(++mstep>=maxStep)break;
tempOA=openA[0]//.splice(getminFopenlist(),1)[0];
//trace(tempOA);
//trace(tempOA.length);
putInclose(tempOA[0],tempOA[1],tempOA[2],tempOA[3]);
if(tempOA[0]==endx&&tempOA[1]==endy)
{
isfindpath=true;
break;
}
//this.getground(tempOA[0],tempOA[1],tempOA[4]);
get45ground(tempOA[0],tempOA[1],tempOA[4]);
}
}
//寻找f最小的
private function getminFopenlist():int
{
var min:uint=0;
for(var isf:int=0;isf<this.openA.length;isf++)
{
if(this.getScore(min+1)>this.getScore(isf+1))
min=isf;
}
return min;
}
//加入到关闭列表
private function putInclose(nx:int,ny:int,px:int,py:int):void
{
closeA.push([nx,ny,px,py])
findA[ny][nx]=1;
//trace("查看openA列表是否被删除:"+openA)
if(openA.length<2)
{
if(isuseOpenlist)openlistHF()
openA=[];
return;
}
openA[0]=openA.pop();
shortBackoutNode();
}
//加入到开启列表
private function putInopenlist(nx:int,ny:int,px:int,py:int,g:int,f:int):void
{
isuseOpenlist=true;
openA.push([nx,ny,px,py,g,f]);
shortopenlist(openA.length);
}
//获取四周的节点
private function getground(sx:uint,sy:uint,g:uint):void
{
//var d:int=this.openA.length;
var Canup:Boolean=isNodeCango(sx,sy-1,sx,sy,g+COST_STRAIGHT);
if(isfindpath)return;
var Canright:Boolean=isNodeCango(sx+1,sy,sx,sy,g+COST_STRAIGHT);
if(isfindpath)return;
var Canlefth:Boolean=isNodeCango(sx-1,sy,sx,sy,g+COST_STRAIGHT);
if(isfindpath)return;
var Candown:Boolean=isNodeCango(sx,sy+1,sx,sy,g+COST_STRAIGHT);
if(isfindpath)return;
//trace("Canup:"+Canup+",Canright:"+Canright+",Canlefth:"+Canlefth+",Candown:"+Candown)
//右上
if(Canup&&Canright&&!isfindpath)isNodeCango(sx+1,sy-1,sx,sy,g+COST_DIAGONAL);
//右下
if(Canright&&Candown&&!isfindpath)isNodeCango(sx+1,sy+1,sx,sy,g+COST_DIAGONAL);
//左上
if(Canup&&Canlefth&&!isfindpath)isNodeCango(sx-1,sy-1,sx,sy,g+COST_DIAGONAL);
//左下
if(Candown&&Canlefth&&!isfindpath)isNodeCango(sx-1,sy+1,sx,sy,g+COST_DIAGONAL);
/*if(d==this.openA.length)
{
trace("没有增加一个元素nx:"+sx+"ny:"+sy);
isNodeCango2(sx,sy-1,sx,sy,g+COST_STRAIGHT);
isNodeCango2(sx+1,sy,sx,sy,g+COST_STRAIGHT)
isNodeCango2(sx-1,sy,sx,sy,g+COST_STRAIGHT)
isNodeCango2(sx,sy+1,sx,sy,g+COST_STRAIGHT)
isNodeCango2(sx+1,sy-1,sx,sy,g+COST_DIAGONAL);
//右下
if(Canright&&Candown&&!isfindpath)
isNodeCango2(sx+1,sy+1,sx,sy,g+COST_DIAGONAL);
//左上
if(Canup&&Canlefth&&!isfindpath)
isNodeCango2(sx-1,sy-1,sx,sy,g+COST_DIAGONAL)
//左下
if(Candown&&Canlefth&&!isfindpath)
isNodeCango2(sx-1,sy+1,sx,sy,g+COST_DIAGONAL)
}*/
}
private function isNodeCango2(nx:uint,ny:uint,px:uint,py:uint,g:uint):void
{
var tempOpenIndex:uint=0;
var hvag:uint=0;
if(nx<0||nx>=mapDataInfo.MAP_X||ny<0||ny>=mapDataInfo.MAP_Y)
{
trace("超过数组大小了:nx="+nx+",ny="+ny)
}
else
trace("是否为障碍物:"+findA[ny][nx]);
}
private function isNodeCango(nx:uint,ny:uint,px:uint,py:uint,g:uint):Boolean
{
var tempOpenIndex:uint=0;
var hvag:uint=0;
if(nx<0||nx>=mapDataInfo.MAP_X||ny<0||ny>=mapDataInfo.MAP_Y)
{
//trace("超过数组大小了:nx="+nx+",ny="+ny)
return false;
}
if(findA[ny][nx]==1)return false;
if(nx==endx&&ny==endy)
{
closeA.push([nx,ny,px,py]);
isfindpath=true;
return false;
}
if(findA[ny][nx]>1)
{
if(findA[ny][nx]>g)
{
tempOpenIndex=getopenindex(nx,ny);
hvag=setH(nx,ny);
findA[ny][nx]=g;
openA[tempOpenIndex]=[nx,ny,px,py,g,g+hvag];
shortopenlist(tempOpenIndex);
}
return true;
}
hvag=setH(nx,ny);
findA[ny][nx]=g;
putInopenlist(nx,ny,px,py,g,g+hvag);
return true;
}
//获取最小的f开启列表路径
private function getopenindex(x:uint,y:uint):uint
{
for(var sj:uint=0;sj<openA.length;sj++)
{
if(x==openA[sj][0]&&y==openA[sj][1])return sj;
}
return undefined;
}
//开启列表排序
private function shortopenlist(indexs:int):void
{
var father:int;
while(indexs>1)
{
father=Math.floor(indexs/2);
//如果该节点的F值小于父节点的F值则和父节点交换
if(this.getScore(indexs)<this.getScore(father))
indexs=Swap(father,indexs);
else
break
}
}
//开启列表取出后进行排序
private function shortBackoutNode():void
{
var checkIndex:int=1;
var temp:int;
while(true)
{
temp=checkIndex
if(checkIndex*2<=openA.length)
{
if(getScore(checkIndex)>getScore(2*temp))
checkIndex=2*temp;
if(temp*2+1<=openA.length)
{
if(getScore(checkIndex)>this.getScore(temp*2+1))
{
checkIndex=2*temp+1;
}
}
}
if(temp==checkIndex)
break;
else
{
Swap(checkIndex,temp);
}
}
}
//获取openlist f值
private function getScore(p_index:int):int
{
//trace(this.openA[0]);
return openA[p_index-1][5];
}
//交换节点
private function Swap(a:uint,b:uint):uint
{
var last:Array=openA[a-1];
openA[a-1]=openA[b-1];
openA[b-1]=last;
return a;
}
//路径估算评分
private function setH(nx:uint,ny:uint):uint
{
return this.set45H(nx,ny);
//return 10 * (Math.abs(endx - nx) + Math.abs(endy - ny))
}
public static function getInstance():SearchRoad
{
if(!_getInstance)
{
_getInstance=new SearchRoad();
}
return _getInstance;
}
//45度的ground
private function get45ground(sx:uint,sy:uint,g:uint):void
{
var temT:Boolean=Boolean(sy&1);
var Canup:Boolean=temT?isNodeCango(sx+1,sy-1,sx,sy,g+COST_STRAIGHT):isNodeCango(sx,sy-1,sx,sy,g+COST_STRAIGHT);
if(isfindpath)return;
var Canright:Boolean=temT?isNodeCango(sx+1,sy+1,sx,sy,g+COST_STRAIGHT):isNodeCango(sx,sy+1,sx,sy,g+COST_STRAIGHT);
if(isfindpath)return;
var Canlefth:Boolean=temT?isNodeCango(sx,sy-1,sx,sy,g+COST_STRAIGHT):isNodeCango(sx-1,sy-1,sx,sy,g+COST_STRAIGHT);
if(isfindpath)return;
var Candown:Boolean=temT?isNodeCango(sx,sy+1,sx,sy,g+COST_STRAIGHT):isNodeCango(sx-1,sy+1,sx,sy,g+COST_STRAIGHT);
if(isfindpath)return;
//trace("Canup:"+Canup+",Canright:"+Canright+",Canlefth:"+Canlefth+",Candown:"+Candown)
//右上
if(Canup&&Canright&&!isfindpath)isNodeCango(sx+1,sy,sx,sy,g+COST_DIAGONAL);
//右下
if(Canright&&Candown&&!isfindpath)isNodeCango(sx,sy+2,sx,sy,g+COST_DIAGONAL);
//左上
if(Canup&&Canlefth&&!isfindpath)isNodeCango(sx,sy-2,sx,sy,g+COST_DIAGONAL);
//左下
if(Candown&&Canlefth&&!isfindpath)isNodeCango(sx-1,sy,sx,sy,g+COST_DIAGONAL);
}
//45度估算评分
private function set45H(nx:uint,ny:uint):uint
{
//return (Math.abs(mapDataInfo.MapArrayElement[endy][endx][0]-mapDataInfo.MapArrayElement[ny][nx][0])+Math.abs(mapDataInfo.MapArrayElement[endy][endx][1]-mapDataInfo.MapArrayElement[ny][nx][1]))*10
//var Bol:Boolean=Boolean(ny&1);
//var w:uint=2;
//w=2;
//True y=int(y/2)+w-x;x=int(y/2)+x;
//false y=w-1+int(y/2)-x;x=int(y/2)+x;
//var Bigy:int=Bol?int(ny/2)+w-nx:w-1+int(ny/2)-nx;
//var Bigx:int=int(ny/2)+nx
/* var _loc_4:uint;
var _loc_5:uint;
var _loc_6:uint;
var _loc_7:uint;
var _loc_8:uint;
_loc_4 = Math.abs(endx - nx) + Math.abs(endy - ny);
_loc_5 = Math.abs(startX - nx);
_loc_6 = Math.abs(startY - ny);
_loc_7 = Math.min(_loc_5, _loc_6);
_loc_8 = Math.abs(_loc_5 - _loc_6) * 10 + _loc_7 * 14;
return _loc_4 * 10 + _loc_8;*/
return (Math.abs(setbigX(endx,endy)-setbigX(nx,ny))+Math.abs(setbigY(endx,endy)-setbigY(nx,ny)))*10
}
//45度y
private function setbigY(nx:uint,ny:uint):uint
{
return mapDataInfo.EleArray[ny][nx][1];
//var Bol:Boolean=Boolean(ny&1);
//return (Bol?Math.floor(ny/2)+mapDataInfo.MAP_X-nx:mapDataInfo.MAP_X-1+int(ny/2)-nx);
}
private function setbigX(nx:uint,ny:uint):uint
{
return mapDataInfo.EleArray[ny][nx][0];
//return Math.floor(ny/2)+nx;
}
}
}