使用组件:一个场地、导航代理、摄像机
实现:进入游戏,鼠标左键点击场景的任意位置,导航代理将自动前往指向位置
步骤
首先我们需要一个场景,新建一平面作为场景地面(如果需要额外的障碍物则自己设置,这里不额外添加)
然后在平面上放置一胶囊体,用作角色(导航代理)
=
给角色挂上两个组件:刚体和导航网格代理
进入窗口 -> AI -> 导航,打开导航配置面板,此时选中我们的地面,在右侧面板进入“对象”,看到有以下三个可更改项:
- navigation static 将物体设置为静态
- generate offmeshlinks 一般用作跳跃或下坡,目前可直接勾选,具体作用后期会有详细解释
- navigation area 里面有三个可选项目,因为是地面所以必须要选择walkable
我们勾选前两项,因为导航代理需要在一个静态的表面上行走,所以必须设置地面为static(此时地面就默认具有碰撞属性了,不需要额外添加刚体)
然后导航区域(navigation area)设置为walkable
=
选择胶囊体(下文简称角色),同样的在导航配置面板中选中“烘焙”,里面的参数我们维持默认不用更改,直接点击右下角的bake进行导航路径烘焙
烘焙完毕,地面出现淡蓝色网格,该网格就是角色可行走的区域
=
最后安排摄像机对准场景,并确保视角足够宽敞
脚本编写
在资源管理器中新建脚本文件NavigationScript.cs,并把该脚本文件直接拖放到角色身上,使脚本的作用对象为角色,之后双击编辑脚本
=
由于我们使用了导航代理组件,就需要在脚本的头部添加有关AI的库,这里导入以下的AI库即可!
using UnityEngine.AI;
=
在主类中添加变量,两个变量分别存储摄像机和导航网格代理
public Camera c; // 获取摄像机 public NavMeshAgent agent; // 获取导航网格代理(就是我们要操纵的人物)
=
我们需要在start方法里面初始化agent变量
因为脚本是挂载角色上的,而角色自带导航网格组件,所以我们使用以下脚本获取该组件(代码中的this就是指代角色本身)
agent=this.GetComponent();
=
下面进入最关键的部分!!!
注意:因为需要持续监测,所以以下代码放在update方法里面
- ray 记录一个从摄像机为起点,射线射到的位置为终点的射线,ScreenPointToRay传入一个参数,为鼠标在屏幕上点击的位置
- raycasthit记录的是射线射到的点所存储的信息
- 我们检测鼠标左键按下(鼠标左键的数字代码是0),随即使用physics里面的发射射线函数,两个参数分别填入ray类型变量和raycasthit类型变量,这里都是固定形式
- 此时我们只需要把角色的目的地设置为射线射到的点的位置就大功告成了!
Ray r = c.ScreenPointToRay(Input.mousePosition); RaycastHit rh; if(Input.GetMouseButtonDown(0)){ if(Physics.Raycast(r,out rh)){ agent.SetDestination(rh.point); } }
=
其他TIPS
这里我们还应该考虑这么一点,如果射线射中的场景对象并非可以行走的表面,或者我们希望角色仅可以在指定表面行走,而让某些特定区域设置为禁行区,那么我们如何做到呢?
事实上,我们可以为禁行区和可行区分别设置不同的名称,当射线发射后,立即监测射中的物体名称,若为可行区则执行设置目的地任务,反之置之不理
END 完整代码示例
using System.Collections; using System.Collections.Generic; using UnityEngine; // 务必记得导入AI库,否则无法使用导航组件相关操作 using UnityEngine.AI; // 实现鼠标左键点击来引导角色前往指定位置 // 这里需要事先烘焙导航场地,且本脚本被赋予的对象角色必须要带有导航网格代理组件 public class FindWay : MonoBehaviour { public Camera c; // 获取摄像机 public NavMeshAgent agent; // 获取导航网格代理(就是我们要操纵的人物) void Start() { // 因为本脚本是赋予人物的,所以从该人物(this)上获取导航网格代理这个组件 agent=this.GetComponent(); } // Update is called once per frame void Update() { // ray是从摄像机处发射一条射线,射线碰到物体后自动停止并返回他的位置 // raycasthit存储着射线碰撞对象的位置 // 以下代码为固定格式,GetMouseButtonDown(0)表示检测鼠标左键按下时发射射线 // agent.SetDestination(rh.point);在射线落下的位置设置为导航代理的目标 Ray r = c.ScreenPointToRay(Input.mousePosition); RaycastHit rh; if(Input.GetMouseButtonDown(0)){ if(Physics.Raycast(r,out rh)){ agent.SetDestination(rh.point); } } } }