网站首页 > 编程文章 正文
12.导航系统
12.1 导航网格
导航网格指的是游戏场景中可以通过的区域。在 Unity 中,我们只需要指定场景中哪些游戏对象参与导航网格的计算,就可以自动生成导航网格。
生成导航网格的步骤:
1.选中所有参与计算的游戏对象,在 Inspector 视图中展开 Static 下列列表选中 Navigation Static 选项。
2.执行菜单:Window -> AI -> Navigation ,打开 Navigation 面板。在该面板中的有 4 个选项卡分别是:Agents、Areas、Bake、Object,选中 Bake 选项卡,单击 Bake 按钮。
3.Bake 完成后在场景中会出现 Bake 网格,网格内的区域就是允许导航的区域。如下图所示:
Bake 属性如下:
- Agent Radius - 代理半径,半径越小, Bake 后网格区域面积越大。
- Agent Height - 代理高度,会影响 Bake 后的门或者桥洞等的高度是否能够通过。
- Max Slope - 最大坡度,可以走上去的最大坡度。
- Step Height - 可以走上去的最大台阶高度。
- Drop Height - 掉落的高度。
- Jump Distance - 在网格间跳跃的最大距离。
12.2 导航代理
导航代理是一个独立的组件,给游戏角色添加 Nav Mesh Agent(导航网格代理)组件后,角色就会在导航区域中进行导航移动。
Nav Mesh Agent 组件属性:
- Agent Type - 代理类型,与 Bake 代理的属性相同,可以在打开的导航面板中删除,也可以为不同的角色添加多个代理类型。
- Base Offset - 基准偏移。
- Speed - 速度,导航网格代理的最大移动速度。
- Angular Speed - 角速度,导航网格代理的旋转角速度。
- Acceleration - 加速,导航网格代理的加速度。
- Stopping Distance - 停止距离,距离目标位置多远停止导航。
- Auto Braking - 自动刹车,到达目标位置后自动减速至停止。
- Radius - 半径,导航网格代理用来计算障碍躲避的半径。
- Height - 高度,导航网格代理用户计算障碍躲避的高度。
- Quality - 质量,躲避障碍质量,质量越高,躲避时的计算越精细,同时性能消耗也越大。
- Priority - 优先级,多个导航网格代理的躲避优先级,数值越大,优先级越高。
- Auto Traverse Off Mesh Link - 是否自动通过网格代理链接。
- Auto Repath - 是否自动重新进行寻路。
- Area Mask - 该导航网格代理允许通过的区域。
使用脚本控制导航:
当场景中导航网格已经生成,游戏角色也挂载了导航代理组件后,接下来就可以为游戏角色添加脚本,在脚本中控制导航进行移动。
示例:单击场景中的位置作为目标点,使角色朝目标点移动,并最终到达目标点。代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class PlayerController : MonoBehaviour
{
private NavMeshAgent _agent;
// Start is called before the first frame update
void Start()
{
_agent = GetComponent<NavMeshAgent>();
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
bool res = Physics.Raycast(ray, out hit);
if (res)
{
Vector3 point = hit.point;
_agent.SetDestination(point);
}
}
}
}
12.3 障碍物
在导航网格生成时,静态障碍物会自动生成好,但在游戏中经常会遇到动态障碍物,对于动态障碍物,需要使用 Nav Mesh Obstacle(导航网格障碍)组件。
Nav Mesh Obstacle 组件属性:
- Shape - 障碍物的形状,可以选择 Box(盒状) 或 Capsule(胶囊状)。
- Center - 障碍物的中心点。
- Size - 障碍物的尺寸。
- Carve - 切割,不切割会作为普通障碍物;切割会对网格进行切割,并对移动区域进行修改。
- Move Threshold - 移动阈值,移动距离超过阈值时才会切割。
- Time to Stationary - 静止时间,障碍物静止时间到达该值后才会进行切割。
- Carve Only Stationary - 是否只在静止时进行切割。
在添加障碍物时,除了要挂载 Nav Mesh Obstacle 组件外,还要为障碍物物体取消勾选 Static 选项。
示例:通过障碍物控制胶囊体移动。
1.新建项目,在场景中添加一个 Plane,缩放为 (2,2,2),添加一个胶囊体,命名为 NPC,并给 NPC 添加 Nav Mesh Agent 组件。
2.在 Project 视图中创建脚本 NPCController,并挂载到 NPC 物体上,代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class NPCController : MonoBehaviour
{
// 导航代理组件
private NavMeshAgent _agent;
// 目标点
private Vector3 targetPosition;
// 是否到达目标点
private bool isArrived = false;
// Start is called before the first frame update
void Start()
{
_agent = GetComponent<NavMeshAgent>();
targetPosition = transform.position + new Vector3(0, 0, 10);
_agent.SetDestination(targetPosition);
}
// Update is called once per frame
void Update()
{
// 获取距离目标点的距离
float dis = Vector3.Distance(transform.position, targetPosition);
if (_agent.remainingDistance < 0.1f)
{
// 在与目标点的距离小于 0.1 的情况下
if (isArrived)
{
// 在开始位置
isArrived = false;
// 向终点移动
targetPosition = transform.position + new Vector3(0, 0, 10);
}
else
{
// 在终点位置
isArrived = true;
// 向开始点移动
targetPosition = transform.position - new Vector3(0, 0, 10);
}
_agent.SetDestination(targetPosition);
}
}
}
3.选中 Plane,执行 Window -> AI -> Navigation ,在 Inspector 视图中勾选 Navigation Static,单击 Bake 选项卡,单击 Bake 按钮。
4.在场景中添加立方体,命名为 Player,位置为(-0.15,1,-3),缩放为(8,2,0.4),给 Player 添加 Nav Mesh Obstacle 组件。
5.在 Project 视图中创建脚本 PlayerController,并挂载到 Player 上,代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
float h = Input.GetAxis("Horizontal");
transform.position += transform.right * h * 0.3f;
}
}
运行游戏,我们会发现,无论怎么样移动障碍物,NPC 都会自动躲避障碍物。
12.4 导航网格链接
网格之间可以设置网格链接。在导航网格生成时,Bake 选项卡中的 Generated Off Mesh Links 中包括 Drop Height(掉落高度)和 Jump Distance(跳跃距离),这个两个属性运行从高台掉落并在高台间跳跃。同时,选中场景中的高台物体(一个或多个),在 Object 选项卡中勾选 Generate Off Mesh Links 选项,然后再在 Bake 选项卡中单击 Bake 按钮,Bake 完成后,可以看到高台的附加自动生成链接,这样角色就可以在链接之间移动了。
上面我们说明的是通过 Bake 自动生成导航网格链接,在实际开发中,我们会需要自己控制网格间的链接,也就是说,我们希望能从某点到另外一点生成一个链接。这时,就需要用到 Off Mesh Link 组件。
Off Mesh Link 组件属性:
Start - 网格链接起始位置的游戏物体。
End - 网格连接结束位置的游戏物体。
Cost Override - 网格链接花费的成本。
Bi Directional - 是否允许双向移动。
Actived - 是否已激活该网格链接。
Auto Update Positions - 是否自动更新位置,勾选后,当起始或结束位置的对象移动时,会更新网格链接。
Navigation Area - 导航区域,网格链接属于的导航区域。
创建网格链接的步骤:
创建一个平面,缩放为(0.03,0.03,0.03),复制一份,并将两个平面放在希望进行网格链接的两个位置。
选择其中一个添加 Off Mesh Link 组件,然后将两个平面分别放在组件的 Start 和 End 处。即可看到生成的网格链接,如下图所示:
12.5 导航区域
在 Navigation 面板上,Areas 选项卡中,一共可以设置 32 个区域,默认设置了 3 个区域,其余区域可以自定义,每个区域都会有颜色和成本的设置。
成本的含义为导航代理网格移动时消耗的体力,导航系统在计算推荐路线时会将成本计算在内。
示例:让胶囊体在规划的路线上移动。
1.新建项目,并在场景中添加 1 个 平面和 8 个 立方体(路面)、1 个胶囊体(角色),形成如下图所示场景:
2.打开 Navigation 面板(Window -> AI -> Navigation),单击 Areas 选项卡,增加一个 Road 区域,设置成本为 1,Walkable 成本为 100。
3.单击一个立方体,在 Navigation 面板中的 Object 选项卡这设置 Navigation Area 为 Road(其他立方体也是如此)。
4.选择 1 个 平面和 8 个 立方体,在 Navigation 面板中 Bake 选项卡中单击 Bake 按钮,完成后如下图所示:
5.在 Project 视图中创建脚本 PlayerController,挂载到胶囊体,代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class PlayerController : MonoBehaviour
{
private NavMeshAgent _agent;
// Start is called before the first frame update
void Start()
{
_agent = GetComponent<NavMeshAgent>();
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
bool res = Physics.Raycast(ray, out hit);
if (res && hit.collider.gameObject.name != "Plane") // 只能在非 Plane 上移动
{
Vector3 point = hit.point;
_agent.SetDestination(point);
}
}
}
}
运行游戏,看看效果,应该是只有在单击立方体时才会移动,移动时是沿着立方体的表面移动的,而不会走 Plane 绿色的区域。
猜你喜欢
- 2024-10-24 3D模型合并纹理集【Python|C#】(3d合并模型之后都变成了灰色怎么办)
- 2024-10-24 揭秘《Sherman》:使用Unity制作影视级光照效果
- 2024-10-24 常用半导体中英对照表2(建议收藏)
- 2024-10-24 基于UGUI实现类似Excel表格功能(有没有类似ug的软件)
- 2024-10-24 体系化的进阶学习内容(体系化的思考)
- 2024-10-24 怀旧游戏不要打开即玩!科普模拟器里各种常用滤镜的原理和效果
- 2024-10-24 按位取反运算符的使用(按位取反+1)
- 2024-10-24 Unity3D 在Hierarchy窗口中显示物体所属Layer
- 2024-10-24 4.Unity摄像机(unity主摄像机)
- 2024-10-24 Unity动画系统详解7:Layer是什么?
你 发表评论:
欢迎- 06-24一个老爸画了超级有爱的365幅画 | 父亲节献礼
- 06-24产品小白看魏则西事件——用产品思维审视百度推广
- 06-24某教程学习笔记(一):13、脚本木马原理
- 06-24十大常见web漏洞——命令执行漏洞
- 06-24初涉内网,提权那些事(内网渗透提权)
- 06-24黑客命令第16集:47种最常见的**网站方法2/2
- 06-24铭说 | 一句话木马的多种变形方式
- 06-24Java隐藏的10倍效率技巧!90%程序员不知道的魔法方法(附代码)
- 最近发表
- 标签列表
-
- spire.doc (70)
- instanceclient (62)
- solidworks (78)
- system.data.oracleclient (61)
- 按键小精灵源码提取 (66)
- pyqt5designer教程 (65)
- 联想刷bios工具 (66)
- c#源码 (64)
- graphics.h头文件 (62)
- mysqldump下载 (66)
- libmp3lame (60)
- maven3.3.9 (63)
- 二调符号库 (57)
- git.exe下载 (68)
- diskgenius_winpe (72)
- pythoncrc16 (57)
- solidworks宏文件下载 (59)
- qt帮助文档中文版 (73)
- satacontroller (66)
- hgcad (64)
- bootimg.exe (69)
- android-gif-drawable (62)
- axure9元件库免费下载 (57)
- libmysqlclient.so.18 (58)
- springbootdemo (64)
本文暂时没有评论,来添加一个吧(●'◡'●)