A*算法的AS实现

	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;
		
		//开放列表,存放节点ID
		private 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;
		
		//节点(数组)地图,根据节点坐标记录节点开启关闭状态和ID
		private 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;
		}
	}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值