请选择 进入手机版 | 继续访问电脑版

查看: 3085|回复: 11

[原创] 进击的新版NavMesh系统:看我飞檐走壁

[复制链接]

15

主题

21

帖子

485

贡献

初级UU族—3级

Rank: 3Rank: 3

积分
485
发表于 2017-7-19 14:03:16 | 显示全部楼层 |阅读模式
本帖最后由 chenjd 于 2017-7-20 04:15 编辑

0x00 前言
unity5.6作为Unity5最后的一个版本,的确起到了一个承上启下的作用。除了上一篇文章《进击的AssetBundles和它的工具们》中提到的AssetBundles-Browser,本文还会介绍另一个在Github开源的,用于Unity5.6+的新寻路功能。
0x01 曾经的痛点
Unity5.6之前的navmesh系统的确操作起来十分容易上手,门槛很低。我们只需要将场景内需要烘焙navmesh的区域勾选上Navigation Static选项,之后就可以在Navigation窗口中烘焙整个场景了。 1372105-f6faebbbffe8a5c6.png
但是曾经的navmesh系统却也存在着一些性能上的和使用场景上的缺陷。
一个常见的问题,由于要预先烘焙场景的navmesh,因此我们很难方便的在运行时动态的修改navmesh。更不用说,有一些游戏的场景并非提前制作好的,需要在运行时动态的生成,这种情况下就无法使用navmesh了。
另一个问题是,如果场景过大的话,烘焙之后的navmesh也会保存很多数据,在运行时会造成一些内存上的开销。
当然,抛开这些不谈,另外一个让我吐槽navmesh的一点就是,它竟然不支持垂直面的导航。
在做一些2d的platform游戏时,我很希望能利用navmesh来实现寻路的逻辑。(图文无关)
但是,不幸的是,之前的navmesh是不支持的。
0x02 组件化的navmesh
不过还好,虽然新的navmesh系统并没有随着unity的正式版本一同发布。但是,我们还是可以通过github来获取这些新的功能:
需要注意的是,Unity的版本要求在5.6以上。
我们可以看到,其实这里只有4个高层的C#脚本文件:

利用这4个脚本文件,就能基本解决我们之前的烦恼了。
其中NavMeshSurface这个脚本将navmesh组件化,利用这个组件就可以很方便的烘焙挂载该组件的对象的navmesh信息,而无需打开一个navigation窗口对整个场景进行烘焙了。我们甚至可以将挂载这个脚本的GameObject烘焙后保存为一个prefab,这个带有navmesh信息的prefab跟其他的prefab一样。

为对象添加NavMeshSurface组件很简单。在这里我们可以看到和之前navigation窗口类似一些设置,但是请注意,这里已经不是整个场景烘焙了。navmesh已经组件化了,它只会烘焙挂载它的对象。
只要点击一下这个组件下的Bake按钮,挂载它的对象就被烘焙好了。
那么GameObject能否挂载多个NavMeshSurface组件呢?这一种需求也的确存在,例如怪物和玩家的寻路策略不同,有些地方玩家能通过而怪物却不能通过。
这的确也是可以的,同一个GameObject能够同时挂载多个NavMeshSurface组件,并且烘焙不同的navmesh供不同的角色使用。
这样,我们针对不同的角色的NavMeshAgent组件设置不同的agent type并和烘焙好的两个navmesh匹配好就可以了。
0x03 飞檐走壁
好了,借助NavMeshSurface组件我们实现了navmesh的组件化。那么是不是我们就能很方便的实现在垂直面上烘焙navmesh了呢?各位想想我们是否能很轻松的让一个游戏对象的角度改变呢?答案是是的。那么这个游戏对象上如果有navmesh信息的话,我们只需要把这个游戏对象从水平变为垂直是否就行了呢?是的。
因此实现游戏角色的在垂直面上飞檐走壁的功能就变得十分简单了。

当然了,在水平面的navmesh和垂直面的navmesh之间我们还会用到NavMeshLink这个组件来链接二者。各位自己在实践的时候需要留意一下这一点。
0x04 在运行时烘焙navmesh
接下来就让我们看看新的navmesh系统带给我们的新的惊喜——在运行时烘焙navmesh。
这是一个很现实的需求,例如一些动态生成场景的游戏,我们无法在一开始就确定这个场景到底是什么样子的,所以也无法使用之前的navmesh系统,因为以前的navmesh只能在editor内烘焙。但是现在我们使用新的navmesh系统就能够很方便的在运行时烘焙navmesh了。

如图,这是一个空场景,在游戏运行之后场景才生成出来场景内的各种道路,此时单击鼠标,navmesh就生成了。
其实在新的navmesh系统内,实现这个机制十分简单。只需要调用游戏对象上挂的NavMeshSurface组件的BuildNavMesh()方法。
void Start(){    surface = GetComponent<NavMeshSurface>();}void Update(){    if (Input.GetMouseButtonDown(0))    {        surface.BuildNavMesh ();    }}
既然navmesh已经可以在运行时创建了,那么我们能否也在运行时实例化一个navmesh的prefab,实时的影响场景内的寻路策略呢?
答案是当然可以。
0x05 场景太大不用愁
自己做过寻路算法的童靴可能会意识到一个问题,就是在做寻路时如果场景过大的话,寻路的数据可能会比较消耗内存。同样在navmesh中,如果场景过大,或者玩家的视野范围有限,一些对玩家当前位置影响不大的场景的其他位置的navmesh数据就有可能造成一些无谓的消耗。
在新的navmesh系统中,我们同样可以优化这个问题,只烘焙玩家周围的navmesh。

这里同样需要NavMeshSurface组件,在inspector视窗我们可以选择collect object中的volume,之后设定size的值就可以值烘焙这个范围内的navmesh了。之后随着玩家的移动,再动态烘焙新的navmesh就可以了。
ref:
【1】High-level NavMesh Building Components
【2】Unite Europe 2017 - Finding the path: New navigation features
各位如果觉得有趣的话,欢迎点个赞。
-EOF-
最后打个广告,欢迎支持我的书《Unity 3D脚本编程》

0

主题

2

帖子

30

贡献

初级UU族—1级

Rank: 1

积分
30
发表于 2017-7-19 17:07:32 | 显示全部楼层
谢谢分享~很赞~

0

主题

69

帖子

965

贡献

中级UU族—1级

Rank: 4

积分
965
QQ
发表于 2017-7-20 00:47:39 | 显示全部楼层
帖子很赞
书也已经读过了,也很赞

0

主题

26

帖子

465

贡献

初级UU族—3级

Rank: 3Rank: 3

积分
465
发表于 2017-7-20 00:50:57 | 显示全部楼层
谢谢分享,数已经买了,准备开始读

15

主题

21

帖子

485

贡献

初级UU族—3级

Rank: 3Rank: 3

积分
485
 楼主| 发表于 2017-7-20 04:16:59 | 显示全部楼层
slfzys 发表于 2017-7-19 17:07
谢谢分享~很赞~

多谢支持

15

主题

21

帖子

485

贡献

初级UU族—3级

Rank: 3Rank: 3

积分
485
 楼主| 发表于 2017-7-20 04:19:06 | 显示全部楼层
fws94 发表于 2017-7-20 00:47
帖子很赞
书也已经读过了,也很赞

多谢支持


15

主题

21

帖子

485

贡献

初级UU族—3级

Rank: 3Rank: 3

积分
485
 楼主| 发表于 2017-7-20 04:25:57 | 显示全部楼层
firepad9 发表于 2017-7-20 00:50
谢谢分享,数已经买了,准备开始读

多谢支持

0

主题

10

帖子

170

贡献

初级UU族—2级

Rank: 2

积分
170
发表于 2017-7-20 04:29:30 | 显示全部楼层
马克一下!

15

主题

21

帖子

485

贡献

初级UU族—3级

Rank: 3Rank: 3

积分
485
 楼主| 发表于 2017-7-21 02:34:31 | 显示全部楼层

0

主题

6

帖子

95

贡献

初级UU族—2级

Rank: 2

积分
95
发表于 2017-7-28 10:52:02 | 显示全部楼层
好东西 期待尽快完善加入正式版本中
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表