介绍
AStar算法,是一种在静态路网中求最短路径的一种算法,是一种启发式的算法.其中,算法当中起点与终点的距离,与算法当中的预估距离越接近,则搜索速度越快.
其实,在AStar算法当中,他的搜索路径的特点与迪杰斯特拉那种毫无章法四处搜索的不同,他是在向着离终点比较近的方向发起的搜索,因此,他的效率自然也就一般的寻路算法要高效了.
当然,这也可以说是启发式算法的优点了
实现思路
AStar算法的实现思路比较简单,就是,向人物当前的节点的邻居节点(可移动的)发起计算,然后选择比较近的那个点,然后以那个点为中心继续开始下一轮的计算,直到到达终点为止
当然,在实现AStar算法之前,首先要掌握几个概念
代价:在计算距离的时候,可以理解为距离
fCost : 起点进过当前点到目标的代价的估计
gCost:起点到当前点的代价
hCost:当前点到终点的估计的代价
fCost = gCost + hCost
OpenSet:开放集合,可以进行计算(但没有被选中)的节点
CloseSet:封闭集合,所有已经计算过而且也被算中的节点
实现
Init
得到StartNode与TargetNode
初始化OpenSet与CloseSet
将初始节点加入到OpenSet当中
Loop (OpenSet.Count > 0)
//找出OpenSet当中fCost最小的点,这个点就是被选中的将要行走的下一个点
currentNode = OpenSet当中fCost最小的点
//将这个点从OpenSet当中移除
OpenSet.Remove(currentNode);
//将这个点加入到ClostSet当中
ClosrSet.Add(currentNode);
if(currentNode == targetNode)
路径已经找到
//若路径没有找到,则查找当前选中的节点的邻居节点,
//计算他们的fCost并加入到OpenSet当中方便下一轮计算
foreach neighbour of the currentNode
//若这个节点是不可以行走,或者已经被算中过了,则跳过这个节点
if (!neighbour.walkable || closeSet.Contains(neighbour))
continue;
//计算这个这个邻居节点的gCost,若gCost更小则说明
//通过currentNode到这个节点的距离更加的短(代价更小)
newGCostToNeighbour = currentNode.gCost +
GetDistance(currentNode,neighbour);
//gCost若更小的话则需要重新计算这个点的fCost和他的父亲节点
//若这个节点不在OpenSet的话,则计算这个节点的fCost与设置父亲节点
//通过设置父亲节点,那么在之后找到路径之后可以通过父亲节点找到整条路径
if(newGCostToNeighbour < neighbour.gCost ||
!openSet.Contans(neighbour)){
neighour.fCost = evaluateFCost(neighour);
neighour.parentNode = currentNode;
if(!OpenSet.Contains(neighour)){
OpenSet.Add(neighbour);
}
}
在Unity当中的实现
首先需要记录Node节点的信息
public class Node {
public Vector3 worldPos;
//对应的路的GameObject
public GameObject road;
public bool walkable;
public int gridX;
public int gridY;
//起点到当前点的代价
public int gCost;
//当前点到终点的预估代价(无视障碍物)
public int hCost;
//当前点到终点的代价
public int fCost
{
get
{
return gCost + hCost;
}
}
public Node(int gridX,int gridY,bool walkable)
{
this.gridX = gridX;
this.gridY = gridY;
this.walkable = walkable;
}
public Node parent;
}
然后是需要一个地图,也就是Grid
这个类主要在于实现地图的建立,与算法关系不大
在这个类当中与算法的唯一关联在于提供了计算节点的邻居节点的方式
public struct GridPosition
{
public int x;
public int y;
}
public class Grid : MonoBehaviour {
enum ClickGridState
{
SetStartPos,
SetEndPos,
Cancel
}
public GameObject cube;
private Dictionary<GridPosition, Node> nodeDic = new Dictionary<GridPosition, Node>();
public List<Node> path;
private GameObject startGO;
private GameObject endGO;
private AStartPathFinding aStartPath;
private Color roadColor;
private ClickGridState currentState;
public float cubeSize = 1f;
readonly int[,] map =
{
{
0,1,0,0,0,0,0,0,0,0,