格子寻路

package dc.framework.pathfinder.grid
{
	import dc.framework.pathfinder.PathGrid;
	import dc.framework.pathfinder.PathGridMap;
	
	import flash.geom.Rectangle;

	/**
	 * 键盘走路
	 * @anchor hannibal
	 * 2013-10-30下午6:09:30
	 */	
	public class GridPathfinder
	{
		static private var m_instance:GridPathfinder;
		/**
		 * 寻路时的步长 
		 */		
		static public const STEP_LENGTH:uint = 4;
		static public const NEARST_STEP:int = 15;
		/**
		 * 寻路成功时的目标点 
		 */		
		private var m_targetPos_X:Number;
		private var m_targetPos_Y:Number;
		
		private var m_last_pos_x:Number;
		private var m_last_pos_y:Number;
		
		private var m_temp_collide_rect:Rectangle;
		//TODO:test
		//private var m_shape:Shape;
		
		//1-right;2-down;3-left;4-up
		private var m_walkDir:int = 0;
		
		/**地图障碍数据*/
		private var m_grid_map:PathGridMap = null; 
		private var m_cur_grid:PathGrid = null;
		/**************************************************************************/
		/*公共方法																  */
		/**************************************************************************/
		public function GridPathfinder()
		{
			m_temp_collide_rect = new Rectangle();
			m_targetPos_X = 0;
			m_targetPos_Y = 0;
		}
		static public function get instance():GridPathfinder
		{
			if(m_instance == null)
			{
				m_instance = new GridPathfinder();
			}
			return m_instance;
		}
		public function setup(grid_map:PathGridMap):void
		{
			m_grid_map = grid_map; 
			
			m_targetPos_X = 0;
			m_targetPos_Y = 0;
		}
		
		public function destroy():void
		{
			
		}
		
		/**
		 * 寻路接口 
		 * @param cur_x
		 * @param cur_y
		 * @param target_x
		 * @param target_y
		 * @param walkDir
		 * @return 
		 * 
		 */		
		public function search(cur_x:Number, cur_y:Number, target_x:Number, target_y:Number, width:Number, height:Number):Boolean
		{
			if(m_grid_map == null)
			{
				return false;
			}
			m_walkDir = 0;
			m_cur_grid = null;
			
			//步长个数
			var stepCount:int = 0;
			
			//上一步的位置
			m_last_pos_x = cur_x;
			m_last_pos_y = cur_y;
			
			//步长增长方向
			var x_step_inc:Number = 0;
			var y_step_inc:Number = 0;
			
			var i:int;
			var bFind:Boolean = false;
			
			//上下
			if(Math.abs(cur_y - target_y) > Math.abs(cur_x - target_x))
			{
				//上
				if(cur_y > target_y)
				{
					stepCount = Math.abs(cur_y - target_y)/STEP_LENGTH;//TODO,存在误差,不过为了速度,先忽视
					y_step_inc = -STEP_LENGTH;
					m_walkDir = 4;
				}
				else//下
				{
					stepCount = Math.abs(cur_y - target_y)/STEP_LENGTH;
					y_step_inc = STEP_LENGTH;
					m_walkDir = 2;
				}
			}
				//左右
			else
			{
				//左
				if(cur_x > target_x)
				{
					stepCount = Math.abs(cur_x - target_x)/STEP_LENGTH;
					x_step_inc = -STEP_LENGTH;	
					m_walkDir = 3;
				}
				else//右
				{
					stepCount = Math.abs(cur_x - target_x)/STEP_LENGTH;
					x_step_inc = STEP_LENGTH;	
					m_walkDir = 1;
				}
			}
			m_temp_collide_rect.width = width;
			m_temp_collide_rect.height = height;
			
			m_cur_grid = m_grid_map.getNodeByPostion(cur_x, cur_y);
			if(m_cur_grid == null)
			{
				return false;
			}
			
			//开始寻路,每次移动一个步长
			for(i=1; i<stepCount; i++)//从1开始,当前位置不判断
			{
				if(_isWalkableRect(cur_x+x_step_inc*i, cur_y+y_step_inc*i))
				{
					m_last_pos_x=cur_x + x_step_inc*i;
					m_last_pos_y=cur_y + y_step_inc*i;
					
					bFind = true;
				}
				else
				{
					if(i == 1)
					{//第一步就不能走:找最优路径
						bFind = findNearestPath(cur_x, cur_y, cur_x + x_step_inc, cur_y + y_step_inc, stepCount);
					}
					m_targetPos_X = m_last_pos_x;
					m_targetPos_Y = m_last_pos_y;
					
					break;
				}
			}
			if(bFind && i==stepCount)
			{
				m_targetPos_X = m_last_pos_x;
				m_targetPos_Y = m_last_pos_y;
			}
			return bFind;
		}
		
		/**************************************************************************/
		/*公共属性																  */
		/**************************************************************************/
		public function getTargetPos_X():Number
		{
			return this.m_targetPos_X;
		}
		public function getTargetPos_Y():Number
		{
			return this.m_targetPos_Y;
		}
		/**************************************************************************/
		/*私有方法																  */
		/**************************************************************************/
		/**
		 * 是否可行走
		 * @param x
		 * @param y
		 * @return 
		 * 
		 */		
		private function _isWalkableRect(x:Number, y:Number):Boolean
		{
			m_temp_collide_rect.x = x - m_temp_collide_rect.width*0.5;
			m_temp_collide_rect.y = y - m_temp_collide_rect.height*0.5/*+10*/;
	
			var grid:PathGrid = m_grid_map.getNodeByPostion(x, y);
			//在障碍里面
			if(grid == null || !grid.walkable)
			{
				return false;
			}

			var i:int;
			var j:int;
			var grid_row:int = grid.row;
			var grid_col:int = grid.col;
			var tempTile:PathGrid;
			switch(m_walkDir)
			{//1-right;2-down;3-left;4-up
				case 1:
					//TODO:现在没有根据人物大小和格子大小做判断
					for(j=0; j<3; j++)
					{
						tempTile = m_grid_map.getNode(grid_col+1, grid_row-1+j);
						if(tempTile == null)
						{
							return false;
						}
						if(!tempTile.walkable && tempTile.rect_collide.intersects(m_temp_collide_rect))
						{
							return false;
						}
					}
					return true;
					
				case 2:
					for(j=0; j<3; j++)
					{
						tempTile = m_grid_map.getNode(grid_col-1+j, grid_row+1);
						if(tempTile == null)
						{
							return false;
						}
						if(!tempTile.walkable && tempTile.rect_collide.intersects(m_temp_collide_rect))
						{
							return false;
						}
					}
					return true;
					
				case 3:
					for(j=0; j<3; j++)
					{
						tempTile = m_grid_map.getNode(grid_col-1, grid_row-1+j);
						if(tempTile == null)
						{
							return false;
						}
						if(!tempTile.walkable && tempTile.rect_collide.intersects(m_temp_collide_rect))
						{
							return false;
						}
					}
					return true;
					
				case 4:
					for(j=0; j<3; j++)
					{
						tempTile = m_grid_map.getNode(grid_col-1+j, grid_row-1);
						if(tempTile == null)
						{
							return false;
						}
						if(!tempTile.walkable && tempTile.rect_collide.intersects(m_temp_collide_rect))
						{
							return false;
						}
					}
					return true;
			}
			return false;
		}
		/**
		 * 查找最近可通过的路径 
		 * 
		 */		
		private function findNearestPath(cur_x:Number, cur_y:Number, temp_x:Number, temp_y:Number, stepCount:int):Boolean
		{
			var sign:int = 1;
			var i:int = 0;
			var j:int = 0;
			var temp_cur_x:Number;
			var temp_cur_y:Number;
			var temp_last_x:Number;
			var temp_last_y:Number;
			switch(m_walkDir)
			{//1-right;2-down;3-left;4-up
				case 1:
				case 3:
					for(i = 0; i<NEARST_STEP; i++)
					{
						for(j = 0; j < 2; j++)
						{
							sign = -sign;
							temp_cur_y = cur_y + sign*i*STEP_LENGTH;
							temp_last_y = temp_y + sign*i*STEP_LENGTH;
							if(_isWalkableRect(cur_x, temp_cur_y))
							{
								if(_isWalkableRect(temp_x, temp_last_y))
								{
									m_last_pos_x = cur_x;
									m_last_pos_y = temp_cur_y;
									return true;
								}	
							}
							else
							{
								return false;
							}
						}
					}
					break;
				
				case 2:
				case 4:
					for(i = 0; i<NEARST_STEP; i++)
					{
						for(j = 0; j < 2; j++)
						{
							sign = -sign;
							temp_cur_x = cur_x + sign*i*STEP_LENGTH;
							temp_last_x = temp_x + sign*i*STEP_LENGTH;
							if(_isWalkableRect(temp_cur_x, cur_y))
							{
								if(_isWalkableRect(temp_last_x, temp_y))
								{
									m_last_pos_x = temp_cur_x;
									m_last_pos_y = temp_y;
									return true;
								}
							}	
							else
							{
								return false;
							}
						}
					}
					break;
			}
			return false;
		}
	}
}

 

posted @ 2013-12-18 10:51  oayx  阅读(681)  评论(0编辑  收藏  举报