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;
}
}
}