A*算法的AS实现

来源:互联网 发布:知天命尽人事什么意思 编辑:程序博客网 时间:2024/06/07 23:19
import flash.display.DisplayObject;import flash.utils.getTimer;/** * @author gjs * @author magicianzrh *  * 使用lx的方式处理 * 用位信息记录碰撞 * 修改为静态方法 * -Ryan *  */ public class Astar {private static var STEP_LENGTH:int = 20;private static var hittest_cost:Number = 0;private static var cancelled:Boolean = false;private static const COST_STRAIGHT : int = 10;private static const COST_DIAGONAL : int = 14;//(单个)节点数组 节点ID 索引private static const NOTE_ID_INDEX : int = 0;//(单个)节点数组 是否在开启列表中 索引private static const NOTE_OPEN_INDEX : int = 1;//(单个)节点数组 是否在关闭列表中 索引private static const NOTE_CLOSED_INDEX : int = 2;//====================================//Member Variables//====================================//最大寻路步数,限制超时返回private static var _maxTryValue : int = 8000;//开放列表,存放节点IDprivate static var _openListAry : Array;//开放列表长度private static var _openCountLength : int;//节点加入开放列表时分配的唯一ID(从0开始),根据此ID(从下面的列表中)存取节点数据private static var _openID : int;//节点x坐标列表private static var _xPointListAry : Array;//节点y坐标列表private static var _yPointListAry : Array;//节点路径评分列表private static var _pathScoreListAry : Array;//(从起点移动到)节点的移动耗费列表private static var _movementCostListAry : Array;//节点的父节点(ID)列表private static var _parentListAry : Array;//节点(数组)地图,根据节点坐标记录节点开启关闭状态和IDprivate static var _noteMapAry : Array;//private static var _wall:Wall;public static function cancel():void{cancelled = true;}/** * 开始寻路 *  * @param p_startX起点X坐标 * @param p_startY起点Y坐标 * @param p_endX终点X坐标 * @param p_endY终点Y坐标 *  * @return 找到的路径(二维数组 : [p_startX, p_startY], ... , [p_endX, p_endY]) */public static function find(p_startX:int,p_startY:int,p_endX:int,p_endY:int,wall:Wall ) : Array {initLists();_wall = wall;_openCountLength = 0;_openID = -1;var mapWidth:uint = wall.mapWidth;var mapHeight:uint = wall.mapHeight;openNote(p_startX, p_startY, 0, 0, 0);var curTryValue : int = 0;var curID : int = new int();var curXPoint : int = new int();var curYPoint : int = new int();var aroundPointsAry : Array = new Array();var checkingID : int = new int();;var costValue : int = new int();var scoreValue : int = new int();while (_openCountLength > 0) {//超越寻路尝试极限返回if (++curTryValue > _maxTryValue) {destroyLists();return null;}if( cancelled ){//trace( "cancelled:" + getTimer() + " ; " );}curID = _openListAry[0];closeNote(curID);curXPoint = _xPointListAry[curID];curYPoint = _yPointListAry[curID]; if (Math.abs(curXPoint - p_endX)<STEP_LENGTH && Math.abs(curYPoint - p_endY)<STEP_LENGTH) {//trace( "finish:" + getTimer() + " ; found : " + curTryValue);//trace("hittest cost : " + hittest_cost );return getPathAry(p_startX, p_startY, curID);}aroundPointsAry = getArounds(curXPoint, curYPoint);for each (var note : Array in aroundPointsAry){costValue = _movementCostListAry[curID] + ((note[0] == curXPoint || note[1] == curYPoint) ? COST_STRAIGHT : COST_DIAGONAL);scoreValue = costValue + (Math.abs(p_endX - note[0]) + Math.abs(p_endY - note[1])) * COST_STRAIGHT ;if (isOpen(note[0], note[1])) {checkingID = _noteMapAry[note[1]][note[0]][NOTE_ID_INDEX];//如果新的G值比节点原来的G值小,修改F,G值,换父节点if(costValue < _movementCostListAry[checkingID]) {_movementCostListAry[checkingID] = costValue;_pathScoreListAry[checkingID] = scoreValue;_parentListAry[checkingID] = curID;aheadNote(getIndex(checkingID));}} else {//将节点放入开放列表openNote(note[0], note[1], scoreValue, costValue, curID);//canvas.beginFill( 0xFF0000 , 0.8 );//canvas.drawCircle( note[0], note[1] , 3 );//canvas.endFill();}}}//开放列表已空,找不到路径destroyLists();//trace( "finish:" + getTimer() + " ; unfound" );return null;}/** * @private static static * 将节点加入开放列表 *  * @param p_xPoint节点在地图中的x坐标 * @param p_yPoint节点在地图中的y坐标 * @param p_scoreValue节点的路径评分 * @param p_costValue起始点到节点的移动成本 * @param p_parentID父节点 */private static function openNote(p_xPoint:int,p_yPoint:int,p_scoreValue:int,p_costValue:int,p_parentID:int) : void{_openCountLength++;_openID++;if (_noteMapAry[p_yPoint] == null){_noteMapAry[p_yPoint] = new Array();}_noteMapAry[p_yPoint][p_xPoint] = new Array();_noteMapAry[p_yPoint][p_xPoint][NOTE_OPEN_INDEX] = true;_noteMapAry[p_yPoint][p_xPoint][NOTE_ID_INDEX] = _openID;_xPointListAry.push(p_xPoint);_yPointListAry.push(p_yPoint);_pathScoreListAry.push(p_scoreValue);_movementCostListAry.push(p_costValue);_parentListAry.push(p_parentID);_openListAry.push(_openID);aheadNote(_openCountLength);}/** *  * 将节点加入关闭列表 * @param p_id需要关闭的点id *  */ private static function closeNote(p_id: int) : void{_openCountLength--;var noteX : int = _xPointListAry[p_id];var noteY : int = _yPointListAry[p_id];_noteMapAry[noteY][noteX][NOTE_OPEN_INDEX] = false;_noteMapAry[noteY][noteX][NOTE_CLOSED_INDEX] = true;if (_openCountLength <= 0) {_openCountLength = 0;_openListAry = [];return;}_openListAry[0] = _openListAry.pop();backNote();}/** * @private static static * 将(新加入开放别表或修改了路径评分的)节点向前移动 */private static function aheadNote(p_index : int) : void{var tmpParent : int = new int();var tmpChange : int = new int();while(p_index > 1) {//父节点的位置tmpParent = Math.floor(p_index / 2);//如果该节点的F值小于父节点的F值则和父节点交换if (getScore(p_index) < getScore(tmpParent)){tmpChange = _openListAry[p_index - 1];_openListAry[p_index - 1] = _openListAry[tmpParent - 1];_openListAry[tmpParent - 1] = tmpChange;p_index = tmpParent;} else {break;}}}/** *  * @private static static * 将(取出开启列表中路径评分最低的节点后从队尾移到最前的)节点向后移动 *  */private static function backNote() : void {//尾部的节点被移到最前面var tmpCheckIndex : int = 1;var tmp : int = new int();var tmpChange : int = new int();while(true) {tmp = tmpCheckIndex;//如果有子节点if (2 * tmp <= _openCountLength) {//如果子节点的F值更小if(getScore(tmpCheckIndex) > getScore(2 * tmp)) {//记节点的新位置为子节点位置tmpCheckIndex = 2 * tmp;}//如果有两个子节点if (2 * tmp + 1 <= _openCountLength) {//如果第二个子节点F值更小if(getScore(tmpCheckIndex) > getScore(2 * tmp + 1)){//更新节点新位置为第二个子节点位置tmpCheckIndex = 2 * tmp + 1;}}}//如果节点位置没有更新结束排序if (tmp == tmpCheckIndex) {break;} else {//反之和新位置交换,继续和新位置的子节点比较F值tmpChange = _openListAry[tmp - 1];_openListAry[tmp - 1] = _openListAry[tmpCheckIndex - 1];_openListAry[tmpCheckIndex - 1] = tmpChange;}}}/** *  * @private static static * 判断某节点是否在开放列表 *  * @param xPoint * @param yPoint *  * @return  *  */ private static function isOpen(xPoint:int,yPoint:int) : Boolean{if (_noteMapAry[yPoint] == null) return false;if (_noteMapAry[yPoint][xPoint] == null) return false;return _noteMapAry[yPoint][xPoint][NOTE_OPEN_INDEX];}/** *  * @private static static * 判断某节点是否在关闭列表中 *  * @param xPoint * @param yPoint *  * @return  *  */ private static function isClosed(xPoint:int,yPoint:int) : Boolean{if (_noteMapAry[yPoint] == null) return false;if (_noteMapAry[yPoint][xPoint] == null) return false;return _noteMapAry[yPoint][xPoint][NOTE_CLOSED_INDEX];}/** * @private static static * 获取某节点的周围节点,排除不能通过和已在关闭列表中的 *  * by magicianzrh * 检测部分我已经抽离了相关函数 */private static function getArounds(p_x : int, p_y : int) : Array{var arr : Array = new Array();var checkX : int = new int();var checkY : int = new int();var canDiagonal : Boolean = new Boolean();//右checkX = p_x + STEP_LENGTH;checkY = p_y;var canRight : Boolean= _wall.canWalk(checkX,checkY); if (canRight && !isClosed(checkX, checkY)) {arr.push([checkX, checkY]);}//下checkX = p_x;checkY = p_y + STEP_LENGTH;var canDown : Boolean = _wall.canWalk(checkX,checkY);  if (canDown && !isClosed(checkX, checkY)){arr.push([checkX, checkY]);}//左checkX = p_x - STEP_LENGTH;checkY = p_y;var canLeft : Boolean = _wall.canWalk(checkX,checkY);  if (canLeft && !isClosed(checkX, checkY)) {arr.push([checkX, checkY]);}//上checkX = p_x;checkY = p_y - STEP_LENGTH;var canUp : Boolean = _wall.canWalk(checkX,checkY);  if (canUp && !isClosed(checkX, checkY)){arr.push([checkX, checkY]);}//右下checkX = p_x + STEP_LENGTH;checkY = p_y + STEP_LENGTH;canDiagonal = _wall.canWalk(checkX,checkY);  if (canDiagonal && canRight && canDown && !isClosed(checkX, checkY)) {arr.push([checkX, checkY]);}//左下checkX = p_x - STEP_LENGTH;checkY = p_y + STEP_LENGTH;canDiagonal= _wall.canWalk(checkX,checkY);  if (canDiagonal && canLeft && canDown && !isClosed(checkX, checkY)){arr.push([checkX, checkY]);}//左上checkX = p_x - STEP_LENGTH;checkY = p_y - STEP_LENGTH;canDiagonal=_wall.canWalk(checkX,checkY);  if (canDiagonal && canLeft && canUp && !isClosed(checkX, checkY)){arr.push([checkX, checkY]);}//右上checkX = p_x + STEP_LENGTH;checkY = p_y - STEP_LENGTH;canDiagonal= _wall.canWalk(checkX,checkY);  if (canDiagonal && canRight && canUp && !isClosed(checkX, checkY)) {arr.push([checkX, checkY]);}return arr;}/** * @private static static * 获取路径 *  * @param p_startX起始点X坐标 * @param p_startY起始点Y坐标 * @param p_id终点的ID *  * @return 路径坐标(Point)数组 */private static function getPathAry(p_startX : int, p_startY : int, p_id: int) : Array{var arr : Array = new Array();var noteX : int = _xPointListAry[p_id];var noteY : int = _yPointListAry[p_id];while (noteX != p_startX || noteY != p_startY){arr.unshift([noteX, noteY]);p_id = _parentListAry[p_id];noteX = _xPointListAry[p_id];noteY = _yPointListAry[p_id];}arr.unshift([p_startX, p_startY]);destroyLists();return arr;}/** *  * @private static static *  * @param p_id * @return 获取某ID节点在开放列表中的索引(从1开始) *  */ private static function getIndex(p_id : int) : int{var i : int = 1;for each (var id : int in _openListAry) {if (id == p_id) {return i;}i++;}return -1;}/** * @private static static * 获取某节点的路径评分 *  * @param p_index节点在开启列表中的索引(从1开始) */private static function getScore(p_index : int) : int{return _pathScoreListAry[_openListAry[p_index - 1]];}/** * @private static static * 初始化数组 */private static function initLists() : void{_openListAry = [];_xPointListAry = [];_yPointListAry = [];_pathScoreListAry = [];_movementCostListAry = [];_parentListAry = [];_noteMapAry = [];}/** * @private static static * 销毁数组 */private static function destroyLists() : void {_openListAry = null;_xPointListAry = null;_yPointListAry = null;_pathScoreListAry = null;_movementCostListAry = null;_parentListAry = null;_noteMapAry = null;_wall = null;}}