前言:在游戏中经常出现怪物自己会走路,人物跟随鼠标点击位置进行移动,那么这些功能是怎么实现的呢?通过本节内容的学习,你会对自动寻路的原理有一个初步的认识。当然了如果想像英雄联盟里面的人物那样带点击的特效的话,还需要用到粒子系统方面的知识,好了,废话不多说了,咱们开始吧
1. 认识网格导航组件
Nav Mesh Agent(网格导航代理)
- Radius:agent的半径,用于计算该agent和其他agent、obstacle的碰撞。
- Height:agent的高度,agent可以通过的头顶障碍最小高度。
- Base offset:agent圆柱碰撞体中心点的偏移值。当Agent创建后,圆柱碰撞体显示过高或过低,用于将其调整到地面。
- Speed:agent移动的最大速度(世界空间中以秒单位计算)
- Angular Speed:agent最大的旋转速度(角度每秒)
- Acceleration:agent最大的加速度(世界空间单位每秒的平方)
- Stopping distance:agent靠近目标时停下的距离
- Auto Braking:自动刹车,当启用的时候agent会在到达终点时慢慢停下,你应该在角色需要平滑地巡逻几个固定点时,禁用它。
- Quality:障碍回避的质量值,如果你有大量的agent就可以降低该值节约CPU的资源,将它设置为0,则只会处理碰撞,不会尝试规避其他agent和obstacle。
- Priority:agent会重视该值比自己小的,而忽略该值比自己大的。该值范围为0到99,数字越低意味着高权限,权限越高(越小的值)会被其他agent重视而回避。
- Auto Traverse OffMesh Link:需要agent自动通过off-mesh link的时候设置为true,当想要使用动画或其他特殊的方法通过off-mesh link时设为false。
- Auto Repath:启用时,agent会在到达局部路径的终点时,尝试再次寻找路径。当没有通向目标的路径时,它会生成一个离目标最近的点作为当前的一个目标。(我尝试下来发现,当目标点不可达,勾选该选项的agent尝试寻找临近目标点的欲望比不勾选的要大)
- Area Mask:AreaMask描述了agent会在哪些烘培的区域中寻找路径。当你准备烘培NavMesh时,你可以指定区域的类型,比如你想让阶梯作为一个特殊的区域,并且禁止某些角色使用阶梯。
在使用Agent的时候,大家可能发现了Agent有Radius属性,在我们烘培NavMesh的时候设置的圆柱体也有Radius属性,两者有什么区别呢?
在寻路的时候有两个阶段,第一阶段只考虑烘培NavMesh并寻找一条可行的路径,而第二阶段Agent就已经在前往目的地的路上了,它会考虑其他agent和obstacle,并尽量避开他们。
烘培时候的Radius就对应第一阶段的生成NavMesh,而Agent上的Radius只在第二阶段使用。就比如说,有一条小径,你有一只大怪是通过不了该路径的,但烘培时候的Radius设置的比较小,虽然Agent的Radius可能设置的很大,但这只大怪还是会使用该小径通过。
所以要理解寻路的两个阶段,再强调一遍,第一阶段没有开始真正的寻路不考虑其他的agent和obstacle,只看NavMesh,而第二阶段Agent已经在行走,而会尽量避开其他agent和obstacle。
Off Mesh Link(分离网格连线)
OffMeshLink组件允许你在区域中给Agent提供一些小近路,使Agent能快速通过,比如跳过栅栏、通过一扇门。
- Start:物体描述的开始点。
- End:物体描述的结束点。
- Cost Override:如果该值是正的,使用它在处理需求路径时计算路径的代价值,否则会使用默认的代价值(游戏物体所属区域的代价值)。如果代价值设置超过3.0,经过该off-mesh link会比经过三倍的默认NavMesh区域还多。当你想用Agent初始化偏爱的路径时,该代价值非常有用。当然最好是在移动中清晰比较长的距离中使用。
- Bi Directional:如果启用,则该link是双向的,否则只能从Start到End。
- Activated:指定该link会不会在寻路的时候使用(在设置为false的时候被忽略)
- Auto Update Position:启用的时候,Off-Mesh Link会自动重新连接start和end的坐标,如果禁用,则只使用启用时候的坐标,即使后来坐标移动了也不会改变。
- Navigation Area:描述link所属的NavMesh区域类型,该区域类型会允许你在相似类型区域中应用该区域的通路代价值,并且防止一些特定的Agent使用该通路,使用Agent的AreaMask属性来控制。
Nav Mesh Obstacle(网格导航障碍)
- Shape:obstacle的几何形状,选择物体最合适的形状,有两种Box方块和Capsule胶囊体。
- Box/Center:方块形状的中心点,与Transform的Position有关。
- Box/Size:方块的大小尺寸。
- Capsule/Center:胶囊体形状的中心点,与Transform的Position有关。
- Capsule/Radius:胶囊体的半径。
- Capsule/Height:胶囊体的高度。
- Carve:当Carve该选项被勾选,Obsacle该物体会在NavMesh上制造一个空洞。
- Move Threshold:Unity会在Obstacle移动该距离下,将其处理为移动状态,使用该属性设置移动更新Carve空洞的频率。
- Time To Stationary:Obstacle停止运动后,经过多少时间(秒)会被处理为静止状态。
- Carve Only Stationary:启用时,Obstacle仅会在静止时被处理成空洞,详见官方文档(废话)。这里有几个小细节需要注意,禁用该选项时,空洞的重新计算是隔一帧计算一次,就是两帧计算一次。然后最好启用该选项,因为每次空洞的重新计算比较费时。官方文档中举了两个适用的场景:木桶、箱子之类会受力停止的启用选项,而像坦克缓慢移动的,则可以禁用该项。
Navigation面板(导航面板)
Agents(网格导航代理)
- Agent Types:导航代理类型
- Name:导航代理名字
- Radius:导航代理半径
- Height:导航代理高度
- Step Height:能上去的台阶高度
- Max Slope:最大的坡度
Areas(导航区域)
- 前三个是Unity内置的Walkable(能走的),Not Walkable(不能走的),Jump(跳)
- 其他的用户用来自定义
Bake(烘焙参数面板)
- Radius:具有代表性的物体半径,半径越小生成的网格面积越大。
- Height:具有代表性的物体的高度。
- Max Slope:斜坡的坡度。
- Ste Height:台阶高度。
- Drop Height:允许最大的下落距离。
- Jump Distance:允许最大的跳跃距离。
- Min Region Area:网格面积小于该值则不生成导航网格。
- Width Inaccuracy:允许最大宽度的误差。
- Height Inaccuracy:允许最大高度的误差。
- Height Mesh:勾选后会保存高度信息,同时会消耗一些性能和存储空间。
Object(物体参数面板)
- Navigation Static:勾选后表示该对象参与导航网格的烘培。
- OffMeshLink Generation:勾选后可跳跃(Jump)导航网格和下落(Drop)。
- Navigation Area:可以导航的区域
2. 使用网格导航组件实现跟随物体位置移动
搭建环境
- 平面障碍物
- 使用Off Mesh Link制作的路径
- 楼梯
- 斜坡
- 断层
- 洞口
3. 烘焙导航网格
-
打开导航面板
-
选中要烘焙的地形对象
-
Navigation>>Object>>All,Navigation Static勾选
- Navigation>>Bake
- 调整半径让其尽可能多的包含地形对象
- 调整高度(可以进入洞口)
- 调整最大坡度(可以上的坡度)
- 调整台阶高度(可以走上楼梯)
- 调整下落高度(可以从高出落下)
- 调整跳的距离(可以跳过断层)
- 点击Bake
-
-
烘焙之后Scene视图中的效果,所有显示蓝色的网格是可以导航到的位置
-
设置能够跳跃断层
- 选中能够跳跃的对象,Navigation>>Object>>All>>Generate OffMeshLinks勾选,然后进入Bake面点击Bake
-
烘焙之后Scene视图中的效果,Plane出现了箭头指向了另一头的Plane
- 使用Off Mesh Link制作的路径
- 创建一个Cube放在第一个Plane的边缘,克隆一个放在第二个Plane的边缘
- 在第一个Cube身上添加Off Mesh Link组件,把第一个Cube拖到组件的Start中,把第二个Cube拖到组件的End中,这样就可以从第一个Plane的第一个Cube的位置到第二个Plane的第二个Cube的位置;中间的黑线就是Off Mesh Link制作的路径
4. 创建角色和跟随物体
-
创建一个胶囊体当作小人
-
创建一个Cube当作跟随物体
5. 在角色身上添加Navigation Mesh Agent组件
6. 脚本
- 功能:让角色导航到跟随物体的位置
- 把脚本挂载到角色身上
- 把跟随物体拖到脚本的实例对象上
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;//人工智能的命名空间
//按下鼠标左键玩家跟随移动
//挂载对象:Player游戏对象
public class Test01 : MonoBehaviour
{
//玩家要到达的位置
public Transform TrCube;
//网格导航代理
private NavMeshAgent mNMA;
void Start()
{
//得到NavMeshAgent组件
mNMA = GetComponent<NavMeshAgent>();
}
void Update()
{
//到指定的位置(终点的位置)
//方法一:通过属性
mNMA.destination = TrCube.position;
//方法二:通过方法
//mNMA.SetDestination(TrCube.position);
}
}
参考文章:Unity3D 官方文档 NavMesh三个组件的翻译与解释 自动寻路需要知道的细节