Unity AI角色尋路 ——A星尋路

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;
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章