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;
  }
 }
}

posted @ 2009-05-07 09:15  Educk  阅读(1689)  评论(3编辑  收藏  举报