`
wgcode
  • 浏览: 576739 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

AS3最优寻路算法

阅读更多
import flash.geom.Point;
import flash.display.Sprite;
import com.qrpg.Algorithm.PathFinding;

var t:int;
var field:Sprite = new Sprite();//地图图层
addChild(field);
var linePath:Sprite = new Sprite();//网格图层

addChild(linePath);
var allNode:Array = []; //节点数据(小格子)
var map:Array = []; //网格
//随机制定网格,35行60列
for (var mapy:int=0; mapy<35; mapy++) {
 if (map[mapy]==undefined) {
  map[mapy] = [];
 }
 //随机生成网格
 for (var mapx:int=0; mapx<60; mapx++) {
  map[mapy][mapx] = Math.random()>.25 ? 0 : 1 ;
 }
}
//var map:Array=[[0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0],[0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,0],[0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,1,1,0,0,1,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1],[0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,0,0,1],[0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0],[1,1,0,0,0,1,1,0,0,0,1,0,1,0,1,0,0,1,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,1,0,1,0,0,0,0,1,1,0,0,0,0],[1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0],[0,0,1,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,1,1,1,1,0,1,1,0,0,0],[0,1,0,1,0,0,0,1,0,0,0,0,0,0,1,0,1,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1],[0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,0,1,1,0,0,1,0,0,1,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0],[1,1,0,0,0,0,1,0,0,0,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,1,1,0,1,0,1,1,0,0,1,1,0,0,0,0],[0,1,0,1,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,1,0,1,1,0,1,0,0,0,1,1,0,0,1,0,1,0,1,1,1,1,0,0,0,1,1,0,1,0,0],[1,1,0,0,0,0,1,1,0,0,0,1,0,0,0,1,1,1,0,1,1,0,0,1,0,1,1,0,0,0,0,0,0,1,0,0,0,1,1,1,0,1,0,1,0,1,0,0,1,0,0,0,0,0,1,1,0,0,0,0],[0,1,0,0,0,0,0,1,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,1,0,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0],[1,0,1,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,1,1,0,1,0,1,1,1,0,0,0,0,1,0,0,1,1,0,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,0,1,0,1,0,1,0,0,1,0,0,0,1,1,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1],[0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0],[1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0],[1,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,0,1,0,1,0,1,1,1,0,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,0,0,1,0,0,0,1,0],[0,1,0,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0],[0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,1,0,1],[0,1,1,1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,1,0,1,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,0,1,0,1,0,0,1,0,0,0,0,0],[0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,1,0,1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1,0],[0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,1,0,0,0,1,1,0,1,0,0,1,0,1,0,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,1,0,0,0,0,1],[0,0,0,0,1,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,1,0,1,0,0],[0,0,1,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1],[0,0,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0],[0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,1,0,0,0,1,1,0,1,1,0,0,0,1,0,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,0],[0,0,0,0,1,0,0,0,0,1,0,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,1,0,1,0,1,0,0,0,0,1,0,0,0],[1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,0,1,0,0,0,0,0,0,0,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,1,1,0,0,0,0,0,0,0,1],[0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,0,0,0,0,0,1,1,1,1,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,1,1,1,0,0,0,0,0,0,0,0],[1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,1,0,0,0,1,1,1,0,1,0,0,1,1,0],[0,0,0,1,0,0,1,0,0,1,1,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,1,1,0,0,1,0,0,1,0,0,0,0,0,1,0,0]];

var w:int = map[0].length; //列长度
var h:int = map.length;  //行长度
var path:Array;    //路径1
var path2:Array;   //路径2
var startpoint:Point = new Point();  //程序启动时的始点
var findPath:PathFinding = new PathFinding(map); //创建包含网格地图的数组(元素是对象)

//在界面上画出节点
for (var py:int=0; py<h; py++) {
 if (allNode[py]==undefined) {
  allNode[py] = [];
 }
 for (var px:int=0; px<w; px++) {
  allNode[py].push(field.addChildAt(new node(), field.numChildren)); //把新建的节点加入到每一行中,列不断增加
  allNode[py][px].p = new Point(px, py);  //用数据索引新建一个当前点的代表坐标点
  allNode[py][px].x=px*10; //设定此节点的坐标
  allNode[py][px].y=py*10;
  //allNode[py][px].gotoAndStop(map[py][px]==0?1:2); //原理和下面相同
  if (map[py][px]==0) { //判断是否不是障碍
   allNode[py][px].stop(); //如果不是障碍,则停止增加节点,增加事件监听
   allNode[py][px].addEventListener(MouseEvent.CLICK, findHandler);
  } else {
   allNode[py][px].gotoAndStop(2);//障碍进入第二帧
  }
 }
}

field.x = 30; //设定图层开始显示的坐标
field.y = 10;
linePath.x = field.x+5; //第一个节点的中心点
linePath.y = field.y+5;


function findHandler(e:MouseEvent):void {
 t = getTimer(); //取得当前的毫秒数
 for (var y:int=0; y<h; y++) {
  for (var x:int=0; x<w; x++) {
   if (allNode[y][x].currentFrame>2) { //不允许 每个节点的帧数大于2
    allNode[y][x].gotoAndStop(1);
   }
  }
 }
 //指定默认的起始点和当前点击的节点的对应P点(*10可得到准确左上角路径),返回一个数组
 path = findPath.path4(startpoint, e.currentTarget.p);
 
 var len:int = path.length;
 
 //把路径的格子设为绿色
 for (var i:int=0; i<len; i++) {
  allNode[path[i].y][path[i].x].gotoAndStop(3);
 }
 if (len==0) {
  trace_mc.text = "无法到达!"; //如果返回路径的长度为0,则表示路径为0 ,不能到达
 } else {
  //path2 = findPath.optimizePath();  
  path2=path;
  //画出路径上的白色线条
  var len2:int = path2.length;
  linePath.graphics.clear();
  linePath.graphics.lineStyle(2,0xffffff,1);
  for (var j:int=0; j<len2; j++) {
   if (j==0) {
    linePath.graphics.moveTo(path2[j].x*10, path2[j].y*10);
   } else {
    linePath.graphics.lineTo(path2[j].x*10, path2[j].y*10);
   }
  }
  startpoint = e.currentTarget.p;
  trace_mc.text = "经过格子"+len+"个,";
 } 
 //计算寻路用了多少时间
 trace_mc.appendText("所用时间:"+(getTimer()-t)+"毫秒。");
}

reset_mc.addEventListener(MouseEvent.CLICK, resetHandler);
function resetHandler(e:MouseEvent):void {

}

 

//
package com.qrpg.Algorithm{
 import flash.geom.Point;
 import com.qrpg.Algorithm.Diagonal;

 public class PathFinding {

  private var _map:Array;//网格地图(元素是对象)
  private var _w:int;//网格地图的宽
  private var _h:int;//网格地图的高
  private var _open:Array;//开放列表
  private var _starPoint:Object;
  private var _endPoint:Object;
  public var path:Array = [];//计算出的路径

  public function PathFinding(map:Array) {
   _map = []; //接收网格地图
   _w = map[0].length; 
   _h = map.length;
   for (var y:int=0; y<_h; y++) {
    if (_map[y]==undefined) {
     _map[y] = [];
    }
    //把每个节点创建成对象,再保存到数组里面
    for (var x:int=0; x<_w; x++) {
     _map[y][x] = {x:x, y:y, value:map[y][x], block:false, open:false, value_g:0, value_h:0, value_f:0, nodeparent:null};
    }
   }
  }
  //四方向寻路
  public function path4(star:Point, end:Point):Array {
   path = [];
   _starPoint = _map[star.y][star.x]; //取得起始点和结束点
   _endPoint = _map[end.y][end.x];
   var __getEnd:Boolean = false; //判断是否到了结束点
   initBlock(); //寻路前的初始化

   var __thisNode:Object = _starPoint; //得到开始点
   
   //循环判断是否到了结束点,直到以最优路径方式找到结束点为止
   while (!__getEnd) { 
    __thisNode.block = true; //把起始点设为障碍
    var __checkList:Array = []; //检查数组
    
    //把当前的周围的四个节点加入检查数组中,等待检查
    if (__thisNode.y>0) {
     __checkList.push(_map[(__thisNode.y-1)][__thisNode.x]);
    }
    if (__thisNode.x>0) {
     __checkList.push(_map[__thisNode.y][(__thisNode.x-1)]);
    }
    if (__thisNode.x<_w-1) {
     __checkList.push(_map[__thisNode.y][(__thisNode.x+1)]);
    }
    if (__thisNode.y<_h-1) {
     __checkList.push(_map[(__thisNode.y+1)][__thisNode.x]);
    }
    
    //开始检测当前节点周围
    var __len:int = __checkList.length;
    for (var i:int = 0; i<__len; i++) {
     //取得周围的每一个节点
     var __neighboringNode:Object = __checkList[i];
     //判断是否是目的地
     if (__neighboringNode == _endPoint) {
      __neighboringNode.nodeparent = __thisNode; //设定此周围节点的父节点,即连接此的节点的上一节点
      __getEnd = true;
      break;
     }
     //是否可通行
     if (__neighboringNode.value == 0) {
      count(__neighboringNode, __thisNode);//计算该节点,传送周围节点和当前中间点过去
     }
    }
    if (!__getEnd) {
     //如果未找到目的地
     if (_open.length>0) {
      //开发列表不为空,找出F值最小的做为下一个循环的当前节点
      __thisNode = _open.splice(getMin(),1)[0];
     } else {
      //开发列表为空,寻路失败
      return [];
     }
    }
   }
   drawPath();
   return path;
  }
  //优化路径
  public function optimizePath():Array {
   var __len:int = path.length;
   var __path:Array = [];
   var diagonal:Array = []; //斜线数组
   var __dLen:int;
   var __cross:Boolean = true;
   var __currentNode:Point = path[0]; //起点
   __path.push(path[0]); //加入到优化后的数组
   for (var i:int=1; i<__len; i++) {
    diagonal = Diagonal.each(__currentNode, path[i]);
    __dLen = diagonal.length;  //返回一个数组
    __cross = true;
    for (var j:int=0; j<__dLen; j++) {
     if (_map[diagonal[j].y][diagonal[j].x].value == 1) {
      __cross = false;
      break;
     }
    }
    if (!__cross) {
     if (i>1) {
      __currentNode = path[(i-1)];
      __path.push(path[(i-1)]);
     }
    }
   }
   __path.push(path[(__len-1)]);
   return __path;
  }

  //寻路前的初始化,设置每个节点的节点属性
  private function initBlock():void {
   for (var y:int=0; y<_h; y++) {
    for (var x:int=0; x<_w; x++) {
     _map[y][x].open = false;  //可以通过
     _map[y][x].block = false;  //障碍
     _map[y][x].value_g = 0;
     _map[y][x].value_h = 0;
     _map[y][x].value_f = 0;
     _map[y][x].nodeparent = null; //寻路过程中的上一点
    }
   }
   _open = [];
  }
  //计算每个节点,接收周围节点和周围节点的中间点
  private function count(neighboringNode:Object, centerNode:Object):void {
   //是否在关闭列表里
   if (!neighboringNode.block) {
    //不在关闭列表里才开始判断
    var __g:Number= centerNode.value_g+10;
    //判断此点是否是障碍
    if (neighboringNode.open) {
     //如果该节点已经在开放列表里
     if (neighboringNode.value_g>=__g) {
      //如果新G值小于或者等于旧值,则表明该路更优,更新其值
      neighboringNode.value_g = __g;
      ghf(neighboringNode); //计算GHF的值
      neighboringNode.nodeparent = centerNode; //把周围节点的上一节点设为中心节点
     }
    } else {
     //如果该节点未在开放列表里
     //添加至列表
     addToOpen(neighboringNode);
     //计算GHF值
     neighboringNode.value_g = __g;
     ghf(neighboringNode);
     neighboringNode.nodeparent = centerNode;
    }
   }
  }
  //画路径
  private function drawPath():void {
   var __pathNode:Object = _endPoint;
   //倒过来得到路径
   while (__pathNode != _starPoint) {
    path.unshift(new Point(__pathNode.x, __pathNode.y));
    __pathNode = __pathNode.nodeparent;
   }
   path.unshift(new Point(__pathNode.x, __pathNode.y));
  }
  //加入开放列表
  private function addToOpen(newNode:Object):void {
   _open.push(newNode);
   newNode.open = true;

  }
  //计算周围节点的ghf各值
  private function ghf(node:Object):void {
   var __dx:Number = Math.abs(node.x-_endPoint.x);
   var __dy:Number = Math.abs(node.y-_endPoint.y);
   node.value_h = 10*(__dx+__dy); //计算周围节点到结束点的X,Y的相差距离(X相差距离+Y相差距离)
   node.value_f = node.value_g+node.value_h; //计算最优路径+XY的相差距离  (总距离)
  }
  //得到开放列表里拥有最小F值的节点在列表里的位置
  private function getMin():int {
   var __len:int = _open.length;
   var __f:Number = 100000;
   var __i:int = 0;
   for (var i:int = 0; i<__len; i++) {
    if (__f>_open[i].value_f) {
     __f = _open[i].value_f;
     __i = i;
    }
   }
   return __i;
  }
 }
}

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics