原理
A* 算法是一种启发式搜索算法,通过代价函数f = g+h,A*算法每次查找代价最低的点作为搜索点,并更新搜索节点列表。最终搜索到目标位置。
需要定义两个列表 (Open和Closed列表):
private List<Tile> openList = new List<Tile>();
private List<Tile> closeList = new List<Tile>();
- 一个记录下所有被考虑来寻找最短路径的格子(称为open 列表)
- 一个记录下不会再被考虑的格子(成为closed列表)
首先在closed列表中添加当前位置(我们把这个开始点称为点 “A”)。然后,把所有与它当前位置相邻的可通行格子添加到open列表中。
引入二个概念:
节点(Node):每个格子都可以称为节点。
代价(Cost):描述角色移动到某个节点时所走的难易程度
通常寻路过程中的代价用f,g,h来表示
g代表从指定节点到相邻节点的代价
h代表从指定节点到目标节点根据不同的估价公式估算出来的代价。
而 f = g + h 表示节点的总代价
public float FValue { get { return GValue + HValue; } }
public float GValue { get; set; }
public float HValue { get; set; }
通常障碍物本身也可以看成是由若干个不可通过的节点所组成,所以 CanPass 是用来标记该节点是否为障碍物(节点)。
在考查从一个节点移动到另一个节点时,总是拿自身节点周围的8个相邻节点来说事儿,相对于周边的节点来讲,自身节点称为它们的父节点
之后根据父节点回溯返回找到路径
public Tile FatherTile;
public bool CanPass;
public List<Tile> nearTiles=new List<Tile>();
重复以下步骤来找到最短路径:
- 将Tile添加到open列表中,该列表有最小的和值。且将这个Tile称为T吧。
- 将T从open列表移除,然后添加T到closed列表中。
- 对于与T相邻的每一块可通行的方块nearT:
· 如果nearT在closed列表中或者是不可通过的:不管它。
· 如果nearT不在open列表中:添加它然后计算出它的和值。
· 如果T已经在open列表中:当我们使用当前生成的路径到达那里时,检查F和值是否更小。如果是,更新它的和值和它的父 节点。
public List<Tile> SearchPath(Tile originTile, Tile targetTile)
{
Tile nowTile = originTile;
openList.Add(nowTile);
bool finded = false;
while (openList.Count > 0)
{
nowTile = openList[0];
for (int i = 0, max = openList.Count; i < max; i++)
{
if (openList[i].FValue <= nowTile.FValue &&
openList[i].HValue < nowTile.HValue)
{
nowTile = openList[i];
}
}
openList.Remove(nowTile);
closeList.Add(nowTile);
// 找到的目标节点
if (nowTile.Equals(targetTile))
{
finded = true;
break;
}
List<Tile> nearTiles = nowTile.nearTiles;
// 判断周围节点,选择一个最优的节点
foreach (Tile near in nearTiles)
{
// 如果是墙或者已经在关闭列表中
if (!near.CanPass|| closeList.Contains(near))
continue;
// 计算当前相领节点现开始节点距离
float newValue = nowTile.GValue + nowTile.ComputeHValue(near);
// 如果距离更小,或者原来不在开始列表中
if (newValue < near.GValue || !openList.Contains(near))
{
// 更新与开始节点的距离
near.GValue = newValue;
// 更新与终点的距离
near.HValue = near.ComputeHValue(targetTile);
// 更新父节点为当前选定的节点
near.FatherTile = nowTile;
// 如果节点是新加入的,将它加入打开列表中
if (!openList.Contains(near))
{
openList.Add(near);
}
}
}
}
openList.Clear();
closeList.Clear();
List<Tile> route = new List<Tile>();
if (finded)
{//找到后将路线存入路线集合
Tile tile = targetTile;
while (!tile.Equals(originTile))
{
route.Add(tile);//将节点添加到路径列表里
Tile fatherHex = tile.FatherTile;//从目标节点开始搜寻父节点就是所要的路线
tile = fatherHex;
}
route.Add(tile);
}
route.Reverse();
return route;
}
ComputeHValue方法用于计算hCost,hCost的计算方式是直接计算距离