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;
	}
}

你可能感兴趣的:(Unity)