适合人群:初学Unity者
在Unity手册中是这样定义的:The Navigation System allows you to create characters which can navigate the game world. It gives your characters the ability to understand that they need to take stairs to reach second floor, or to jump to get over a ditch.
大致翻译为:导航系统允许你创建一个在游戏世界中能导航的角色。它可以让你的角色有能力去理解他们需要去爬楼梯到二楼,或者跳越一条沟渠。(本人英语翻译能力有限哈!)
首先需要将地形设置为Navigation Static,如下图所示:
如果有不想烘焙的地方,取消勾选即可。打开Window-Navigation导航窗口,选择Bake页面,如下所示:
设置好后,可以点击Bake进行烘焙,导航网格效果如下图所示:
为角色添加NavMeshAgent组件,用来控制角色在导航网格上移动,Unity版本不同,可能面板不太一样,如上所示:
常用API:
用来设置路径估值(Cost),比如走楼梯,消耗体能20,而坐电梯,消耗体能5,自然会选择后者方式。
设置完消耗代价后,在Object面板中设置类型
Unity内置了三种area,Walkable设置可行走区域,NotWalkable设置不可行走区域,如果不想让角色行走的区域,可以设置成这个。需要注意,做了修改,一定要重新烘焙网格,设置才会有效哦!
地形之间可能有间隙,形成沟壑,或者是高台不能跳下,导航网格处于非连接的状态,角色无法直接跳跃,要绕一大圈才能到达目的地。off mesh links用于解决这种问题。
可以自动或者手动创建off mesh links,需要先设置bake选项卡中的Drop Height或者Jump Distance属性,前者控制跳跃高台最大高度,后者控制跳跃沟壑的最大距离。
选中需要创建Links的对象,在Object 选项卡内勾选Generate OffMeshLinks,再重新烘焙即可。需要注意,这里平台1设置了Links,而平台2没有设置。此时,角色只能从平台1跳到平台2,如下图箭头所示:
手动添加Links,需要为地形对象添加off mesh link组件,可以创建两个空对象,分别用来控制跳跃的开始和结束点,如下所示:
实现点击目标,自动寻路功能,效果如下:
前期准备:渲染好导航网格,在玩家身上挂载Nav Mesh Agent组件
添加如下脚本:
public class Player : MonoBehaviour
{
private NavMeshAgent navMeshAgent;
private void Start()
{
navMeshAgent = gameObject.GetComponent();
}
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray,out hit))
{
Transform parent = hit.collider.transform.parent;
if (parent != null && parent.name.Equals("Env"))
{
navMeshAgent.SetDestination(hit.point);
}
}
}
}
}
下面实现代码控制角色移动,navMeshAgent.updatePosition = false; navMeshAgent.updateRotation = false;可以禁止Agent更新位置和旋转。但会造成Agent的绿框和角色分离,如下图所示,设置绿框的位置和角色位置相同即可解决问题,navMeshAgent.nextPosition = transform.position;
public class Player : MonoBehaviour
{
private NavMeshAgent navMeshAgent;
private void Start()
{
navMeshAgent = gameObject.GetComponent();
//禁用NavMeshAgent更新角色位置
navMeshAgent.updatePosition = false;
navMeshAgent.updateRotation = false;
}
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray,out hit))
{
if (hit.collider.name.Equals("Floor"))
{
navMeshAgent.nextPosition = transform.position;
navMeshAgent.SetDestination(hit.point);
}
}
}
Move();
}
private void Move()
{
if (navMeshAgent.remainingDistance < 0.5f) return;
navMeshAgent.nextPosition = transform.position;
if (navMeshAgent.desiredVelocity == Vector3.zero) return;
Quaternion targetQuaternion = Quaternion.LookRotation(navMeshAgent.desiredVelocity,Vector3.up);
transform.rotation = Quaternion.Lerp(transform.rotation, targetQuaternion, Time.deltaTime *3);
transform.Translate(Vector3.forward * Time.deltaTime*3);
}
}
其他可以参考学习的博客:
https://www.jianshu.com/p/70da4f9461ae
https://blog.csdn.net/janeky/article/details/17457533
https://www.jianshu.com/p/f9a32d293d2f