随感通过这篇文章http://blog.youkuaiyun.com/v_july_v/article/details/6093380
顺手用as亲自实现一个A*寻路算法,g(n),h(n) 函数暂且随意用距离表示,可优化
Node.as
package AStar
{
/**
*节点
* @author lake
* 地图为 平面正方形
*/
public class Node
{
/**
* 行索引
*/
public var mRowIndex :int;
/**
*列索引
*/
public var mColIndex :int;
/**
*是否阻拦
*/
public var isBlock :Boolean = false;
public var g :Number = 0;
public var h :Number = 0;
public function Node()
{
}
public function get f():Number
{
return g + h;
}
public function get x():Number
{
return mColIndex * 20;
}
public function get y():Number
{
return mRowIndex * 20;
}
}
}
FindPath.as
package AStar
{
import flash.geom.Point;
/**
*寻路
* @author lake
*
*/
public class FindPath
{
/**
* 开放列表节点
*/
public var openList :Array = [];
/**
* 关闭列表节点
*/
public var closeList :Array = [];
/**
*所有节点列表
*/
public var allNodeList :Array = [];
/**
*表示从起始搜索点到当前点的代价(通常用某结点在搜索树中的深度来表示)
*/
public var gValue :Number;
/**
*表示启发式搜索中最为重要的一部分,即当前结点到目标结点的估值
*/
public var hValue :Number;
/**
* 地图宽度
*/
public var mapWidth :int;
/**
* 地图高度
*/
public var mapHeight :int;
/**
* 格子宽度
*/
public var gridWidth :int;
/**
* 格子高度
*/
public var gridHeight :int;
/**
*行数
*/
public var mapRow :int;
/**
* 列数
*/
public var mapCol :int;
/**
* 起始
*/
public var startNode :Node;
/**
* 终点
*/
public var endNode :Node;
public function FindPath()
{
}
/**
*初始化
* @param mapWidth
* @param mapHeight
* @param gridWidth
* @param gridHeight
*
*/
public function initPaths(mapWidth:int,mapHeight:int,gridWidth:int,gridHeight:int):void
{
allNodeList = [];
this.mapWidth = mapWidth;
this.mapHeight = mapHeight;
this.gridWidth = gridWidth;
this.gridHeight = gridHeight;
var i:int,j:int;
mapRow = mapHeight / gridHeight;
mapCol = mapWidth / gridWidth;
var node :Node;
for(i = 0;i<=mapRow;i++)
{
allNodeList.push([]);
for(j = 0;j<=mapCol;j++)
{
node = new Node();
node.mRowIndex = i;
node.mColIndex = j;
allNodeList[i][j] = node;
}
}
}
/**
* 寻路
* @param startPoint
* @param endPoint
* @return
*
*/
public function findPathByPoint(startPoint:Point,endPoint:Point):Array
{
var fres :Array = [];
var startNode :Node = allNodeList[int(startPoint.y / gridHeight)][int(startPoint.x / gridWidth)];
var endNode :Node = allNodeList[int(endPoint.y / gridHeight)][int(endPoint.x / gridWidth)];
this.startNode = startNode;
this.endNode = endNode;
var isEnd:Boolean=false;
var thisNode:Node = startNode;
while (!isEnd)
{
var checkList:Array=getNearNodeList(thisNode);
//开始检测当前节点周围
var len:int=checkList.length;
for (var i:int=0; i < len; i++)
{
//周围的每一个节点
var nearNode:Node=checkList[i];
//判断是否是目的地
if (nearNode == endNode)
{
isEnd=true;
closeList.push(thisNode);
closeList.push(endNode);
break;
}
//是否可通行
if (nearNode.isBlock == false)
{
countNode(nearNode);
}
}
if (!isEnd)
{
//如果未找到目的地
if (openList.length > 0)
{
//开发列表不为空,找出F值最小的做为下一个循环的当前节点
closeList.push(thisNode);
openList.sortOn(["f"],[Array.NUMERIC]);
thisNode = openList.splice(0,1)[0];
}
else
{
//开发列表为空,寻路失败
return [];
}
}
}
fres = closeList;
return fres;
}
/**
*寻找周围节点 (八方向)
* @param node
* @return
*
*/
public function getNearNodeList(node :Node):Array
{
var nodeList :Array = [];
var leftIndex :int = (node.mColIndex - 1)<0?0:(node.mColIndex - 1);
var topIndex :int = (node.mRowIndex - 1)<0?0:(node.mRowIndex - 1);
var rightIndex :int = (node.mColIndex + 1)>mapCol?mapCol:(node.mColIndex + 1);
var downIndex :int = (node.mRowIndex + 1)>mapRow?mapRow:(node.mRowIndex + 1);
var targetNode :Node;
for(;topIndex<=downIndex;topIndex++)
{
for(var tLeftIndex :int = leftIndex;tLeftIndex <= rightIndex;tLeftIndex++)
{
targetNode = allNodeList[topIndex][tLeftIndex];
if(targetNode != node)
{
nodeList.push(targetNode);
}
}
}
return nodeList;
}
/**
* 计算节点权值
* @param node
*
*/
private function countNode(node :Node):void
{
node.g = g(node);
node.h = h(node);
if(closeList.indexOf(node) == -1)
{
openList.push(node);
}
}
private function g(node :Node):Number
{
var value :Number = 0;
//value = -Math.sqrt(Math.pow(node.mRowIndex - startNode.mRowIndex,2)+ Math.pow(node.mColIndex - startNode.mColIndex,2));
return value;
}
private function h(node :Node):Number
{
var value :Number = 0;
value = Math.sqrt(Math.pow(node.mRowIndex - endNode.mRowIndex,2)+ Math.pow(node.mColIndex - endNode.mColIndex,2));
return value;
}
}
}
测试代码:(Flash builder 4.5 开发坏境)
FindPathTest.as
package
{
import AStar.FindPath;
import AStar.Node;
import flash.display.Sprite;
import flash.geom.Point;
[SWF(width="800",height="600",backgroundColor="#cccccc",frameRate="25")]
public class FindPathTest extends Sprite
{
public function FindPathTest()
{
var startPoint :Point = new Point(80,20);
var endPoint :Point = new Point(500,300);
var fp :FindPath = new FindPath();
fp.initPaths(800,600,20,20);
drawGrid(800,600,20,20);
this.graphics.beginFill(0xff0000);
this.graphics.drawCircle(startPoint.x + 10,startPoint.y + 10,8);
this.graphics.drawCircle(endPoint.x + 10,endPoint.y + 10,8);
this.graphics.endFill();
var paths :Array = fp.findPathByPoint(startPoint,endPoint);
this.graphics.beginFill(0x00cc00);
for each(var node :Node in paths)
{
this.graphics.drawCircle(node.x + 10,node.y + 10,3);
}
this.graphics.endFill();
}
private function drawGrid(mw:int,mh:int,gw:int,gh:int):void
{
var i:int,j:int;
var mapRow :int = mh / gh;
var mapCol :int = mw / gw;
this.graphics.lineStyle(1,0x0000cc);
for(i = 0;i<mapRow;i++)
{
this.graphics.moveTo(0,i * gh);
this.graphics.lineTo(mw,i * gh);
}
for(j = 0;j<mapCol;j++)
{
this.graphics.moveTo(j * gw,0);
this.graphics.lineTo(j * gw,mh);
}
}
}
}
A*算法与广度、深度优先和Dijkstra 算法的联系就在于:当g(n)=0时,该算法类似于DFS,当h(n)=0时,该算法类似于BFS。且同时,如果h(n)为0,只需求出g(n),即求出起点到任意顶点n的最短路径,则转化为单源最短路径问题,即Dijkstra算法。这一点,可以通过上面的A*搜索树的具体过程中将h(n)设为0或将g(n)设为0而得到。