Unity 官方 A*Pathfinding Project 插件的使用學習筆記
A* Pathfinding Project 是基於Unity擴展編輯器開發的一款尋路插件,尋路原理是基於AStar尋路新算法,,也稱作A* 尋路算法。
一、A* 尋路 VS 導航網格NavMesh尋路:
- A*尋路:
動態
尋路,適用於場景狀態變化大的,比如遊戲,但CPU消耗高 - NaveMesh:
靜態
尋路,適用於場景狀態不怎麼變化的,CPU消耗低
二、插件的使用
- 創建Ground ,指定Layer層:Ground (地面)
- 創建Obstacles,指定Layer層:Obstacles (障礙物)
- 創建Empty,命名AStarPathfinder,添加腳本組件Pathfinder(Astar Path)
- 選擇Grid Graphs 網格尋路:
* Width/Depth(nodes):網格節點數(網格範圍大小)
* Aspect Ratio:單位網格的長寬比
* Center:設置網格的位置,若發現網格位置不理想,沒關係,點擊Snap Size 即可
* Erosion iterations:默認值爲0,調整該值避免人穿障礙物,親測值爲 1 即可 - Collision testing:Mask >> 選擇Obstacles,指定障礙物
- Height testing:Mask >> 選擇Ground,指定地面
- 點擊Scan 按鈕,生成可行走區域
- 創建Capsule(或者指定模型),命名Player, 代表AI角色,添加腳本組件 Seeker 用於計算路徑
- Player對象添加 SimpleSmoothModifier 腳本組件,用以平滑Player的移動路線(默認的路線曲曲折折的,人物移動時不平滑)
- 創建 AstarPlayer 腳本,編輯代碼控制Player尋路:
三、代碼示例
using Pathfinding;
public class AstarPlayer:MonoBehaviour
{
private float _moveSpeed = 10.0f; //AI角色移動速度
private Seeker _seeker; //A*尋路路徑計算組件
private Vector3 _targetPoint; //尋路目標點
private Path _path; //尋路計算出的路徑
private Vector3 _playerCenterY; //AI角色Y軸座標值
private Vector3
private int _curPathPoint; //當前路徑點數
private bool _stopMove = true; //標記AI角色停止移動
void Start()
{
_seeker = GetComponent<Seeker>();
if(_seeker == null)
{
Debug.Log("Seeker Component is null!");
return;
}
}
private void FixedUpdate()
{
if(_path != null && !_stopMove)
{
//計算Player當前位置到下一個目標點的方向
Vector3 temp = _path.VectorPath[_curPathPoint];
Vector3 nextPoint = new Vector3(temp.x, temp.y + _playerCenterY, temp.z);
Vector3 dir = (nextPoint - transform.position).normalized;
//計算Player當前位置到下一個目標點的距離
float offset = Vector3.Distance(transform.position, nextPoint);
if(offset < 0.1f)
{
transform.position = nextPoint;
_curPathPoint++;
//檢查Player是否走到最後一個目標點,是,完成移動
CheckLastPoint();
}
else
{
//計算一幀移動多少距離
Vector3 distance = dir * _moveSpeed * Time.deltTime;
if(distance.magnitude > offset)
{
//重新計算移動距離
distance = dir * offsest;
_curPathPoint++;
//檢查是否到達最後一個節點
CheckLastPoint();
}
transform.localPosition += distance;
}
}
}
private void Update()
{
//監聽鼠標左鍵按下
if(Input.GetMouseButtonDown(0))
{
//用射線創建 TargetPoint
Ray ray = Camera.main.ScreenPointToRay(Input.GetMousePosition);
RaycastHit hit;
//利用物理引擎發射一條射線,返回true,說明射線與物體發生碰撞
if(Physics.RaycastHit(ray,out hit,100))
{
_targetPoint = hit.point;
//計算路徑
_seeker.StartPath(transform.position, _targetPoint, OnPathCompeleted);
}
}
}
//檢查到達最後一個目標點
private void CheckLastPoint()
{
if(_curPathPoint == _path.VectorPath.Count)
{
_curPathPoint = 0;
_path = null;
_stopMove = true;
}
}
//尋路路徑計算完成時回調
private void OnPathCompeleted( Path path)
{
_path = path;
_curPathPoint = 0;
_stopMove = false;
}
}