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;
}
}
A*算法的AS实现
最新推荐文章于 2024-08-05 22:15:59 发布