Unity3d 實現 A * 尋路演算法
阿新 • • 發佈:2019-02-13
原理
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的計算方式是直接計算距離