格子寻路
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; } } }