以下内容笔者个人翻译自:http://www.theknightsofunity.com/

游戏中的许多角色经常需要绕过关卡种中的障碍物。正是因为这是一个游戏中非常常见的情形,Unity提供了内置的寻路解决方案,叫做NavMesh。在这篇教程中,你将通过NavMesh实现点击移动。

本教程使用版本:Unity 2020.1.17


游戏中的寻路系统

游戏中的AI角色往往需要找到一条最佳路径来到达它们的目的地。有非常多的寻路算法可供你选择。不过,除了一些少数情况外,A* 算法会是一个很好的选择。

A* (or A-star)

A算法通常用于各种计算环境下的寻路 —— 它不是Unity特有的,下面这篇文章讨论了A算法在IOS开发环境下的内容:https://www.raywenderlich.com/3016-introduction-to-a-pathfinding。如果更深入的了解,这篇文章提供了一个图解式交互指南:https://www.redblobgames.com/pathfinding/a-star/introduction.html。另外还有一篇文章解释了独立与任何技术栈的A*算法的步骤:https://gist.github.com/jcward/45afd22560939aaae5c75e68f1e57505

Navigation Meshes

上面提到的A文章中讨论了在方形网格上的寻路问题,但是该算法则不需要像这样的地图。A也可以在任何形状中实现。该算法所需要的仅仅是一张连通节点图,而方形网格只是其中一种。你甚至可以在真实世界地图中使用A*:道路的交叉口都是节点,而道路是节点与节点之间的连接。

游戏中通常用网格来表示寻路图。就像3D模型一样,用于寻路的图可以由边连接顶点来表示【官方解释:https://docs.unity3d.com/Manual/nav-InnerWorkings.html】。诸如这样的网格被称为 Navigation Mesh,因此Unity使用了一个缩写名 NavMesh。

Unity内置了基础的NavMesh功能,但有一个叫做NavMesh Components的开源项目提供了更健壮的网格生成与寻路功能。当你设置你的项目时,你可以从GitHub上下载它。现在我们看看如何使用它们吧。


生成NavMesh

首先,创建一个空的GameObject并命名为NavMesh。导航网格将从该对象上生成,并附加到该对象上。接下来,添加NavMeshSurface组件到这个对象上。在Inspector面板你可以看到一系列的导航设置,以及一些管理网格生成的按钮。

点击Bake按钮,Unity将使用默认设置来创建一个导航网格。

理解NavMeshSurface

上面发生了什么呢?虽然底层代码是相当复杂的,但是主要的步骤却不难理解。NavMeshSurface首先使用自己GameObject的旋转角度来决定向上的方向。然后它定义了场景面向方向的表面。(在该案例中,它们都是平坦的,但是NavMeshSurface同样也作用于地形或者其他不规则的网格。)

NavMesh系统必须确定哪些表面是可以行走的。游戏角色有不同的形状和大小。比如小猫的可行走区域不同于一个人类或巨型机器人。这就是NavMeshSurface顶部图标的作用所在。

该图说明了将在这个网格上行走的特定类型代理的属性,例如其半径和高度。(你可以在代理类型下拉列表中访问这些设置,但本教程不需要这些设置。)

NavMesh系统使用这些设置来确定代理的去向。当系统发现一个足够平、宽、高的区域时,它将该区域标记为可行走的区域。然后,它生成一个平面导航网格,在场景中以蓝色区域显现。


调整NavMesh的层级

首先,玩家周围的网格有一个洞。默认情况下,场景中的一切都被认为是导航的潜在障碍。你需要明确告诉NavMeshSurface不要将玩家作为一个障碍物。

NavMeshSurface有一个下拉菜单叫做Include Layers。如果你在下拉菜单中取消选择一个图层,网格生成系统会忽略该图层上的对象。按照以下步骤将玩家放到一个新图层上,然后将该图层从网格中移除:

  1. Hierarchy面板中选中Player
  2. Layer下拉菜菜单中,选择Add Layer
  3. 添加一个新的Layer命名为Player
  4. 再次选中Player,修改其LayerPlayer
  5. 如果出现一个弹窗问你是否对子物体也进行修改,选择是。
  6. 选中NavMesh
  7. 在Inspector面板中,打开Include Layers下啦菜单,点击Player进行反选。

现在Unity明白了Player不是导航障碍物了。点击Bake来重新生成导航网格,空洞就消失了!

从NavMesh中移除一个对象

但还有一个问题。选中NavMesh,看看右上角区域。顶部的蓝色方块意味着导航系统将其视为地板的一部分,也就是说,它会被作为有效路径的一部分。然而玩家应当只能在地板上行走,不能在墙上行走!但你不能像对待玩家那样忽略那个方块。它仍然需要被当做一个障碍物,这样NavMesh就不会生成它的路径。

幸运的是,你可以用另一个组件NavMeshModifier来处理这个问题。下面是设置它的步骤:

  1. 在面板中选中那个角落区域的物体。
  2. 添加一个NavMeshModifier组件。
  3. 在这个组件中,选择启用Overrid Area
  4. 将Area Type改为Not Walkable

现在Unity明白那个角落是一个障碍而不是一个可行走的区域了,重新bake问题就解决了!

通过这些调整,你已经正确地设定了导航,可以让玩家在迷宫中跑起来了。

移动角色

在导航网格上移动一个对象是NavMeshAgent组件的工作。它计算着导航网格中的路径,从当前位置到你给它的任何目的地(或者最近的点如果它不在网格上)。

设置NavMeshAgent组件

首先,选择玩家并添加一个NavMeshAgent组件。默认设置的移动速度有点迟缓,但是你可以将其调整得更敏捷。在NavMeshAgent上,将速度提升到5,角速度提升到360,加速度提升到10。

现在你只需要一个脚本来设置NavMeshAgent的目的地,NavMesh会处理接下来的事情。

设置NavMeshAgent的目的地

在Assets/RW/Scripts目录下创建一个PlayerMovement.cs的脚本。添加一个命名空间引用:

using UnityEngine.AI;

该库引入了NavMesh相关类。

接下来在类顶部声明两个变量:

private Camera cam;
private NavMeshAgent agent;

然后在Start方法中添加如下两行:

cam = Camera.main;
agent = GetComponent<NavMeshAgent>();

Camera类有一个方便的方法,可以将鼠标在屏幕上的位置转换为游戏世界中的位置。将该位置传递给代理作为其目的地。

在Update方法中添加:

if (Input.GetMouseButtonDown(0))
{Ray ray = cam.ScreenPointToRay(Input.mousePosition);}

这段代码检查每一帧,看看鼠标按钮是否被按下。如果是,它构造一条从相机到鼠标位置的射线。你将在下一步使用射线。

接下来在if语句中添加这些行:

if (Physics.Raycast(ray, out RaycastHit hit))
{agent.SetDestination(hit.point);
}

这段代码将射线发送到游戏世界中,并检查它是否击中了任何东西。(注意射线只会击中带有碰撞器的物体。)如果光线确实击中了什么东西,它会把击中的位置存储在hit.point。然后,您可以简单地将该位置提供给agent 作为其目的地。


优化Navigation Mesh

现在角色已经成功地在迷宫中移动了,你可以通过指定导航区域来让导航网格变得更有趣。当你把角落块设置为不可行走时,你实际上已经调整了一个导航区域。但你能做的远不止打开或关闭某个区域。

为了表示更复杂的环境,你可以指定不同的区域,这些区域具有不同权重,定义该区域移动的困难程度(或不受欢迎程度)。NavMesh代理将倾向于避开成本高的区域,即使从技术上讲穿越该区域的路径较短。想象一下在不同地形上移动的军事单位:如果他们抄近路穿过山脉,路径可能会更短,但他们更喜欢穿过开阔的田野绕山而行。在导航网格中使用不同权重的区域来表示这种情况很简单。

分配导航区域

首先,向导航系统添加一个新区域。选择WindowAINavigation。然后,选择Areas选项卡来查看这个项目中定义的所有导航区域。在第一个可用行中键入名称Water,并将其Cost设置为5。

回到场景视图。在迷宫的子物体中寻找并选择Water。(如果它在导航栏后面,您可能需要选择Inspector选项卡再次查看它。)添加一个NavMeshModifier组件,打开Override Area并将Area Type改为Water。然后再把网格烘焙一遍。

启动游戏,点击网格,看看玩家的寻径方式是如何变化的。例如,尝试将玩家放在右上角,然后点击角落方块的下方。到达目的地的最短路径是穿过水。相反地,玩家需要在较长的路径中进行导航。

你现在知道了在Unity中使用NavMesh寻路的基础知识!记住三个主要的组件:NavMeshSurface, NavMeshModifierNavMeshAgent

使用NavMesh系统,你可以做更多的事情。你可以使用NavMeshAgent设置定义不同类型的代理,创建在墙壁或天花板上行走的角色,或者探索将多个网格连接在一起。或者你可以尝试运行时生成。运行时生成指的是在游戏运行时创建一个导航网格,而不是像你在本教程中所做的那样提前烘烤一个导航网格。

尽管NavMesh免费又好用,但是许多开发者更喜欢A*寻径方式。如果游戏需要,你也可以尝试一下。

【Unity】游戏寻路系统—NavMesh入门(个人翻译)相关推荐

  1. Unity Navigation寻路系统并画出指引线

    前言 寻路系统是游戏中很常用的一个功能,角色要达到某一点,需要系统给出一个路径,这样可以帮助玩家规划出路径,提示玩家到达,这种功能在各种类型的游戏中都有大量的应用 本案例通过Navigation实现寻 ...

  2. Unity导航寻路系统插件--A* Pathfinding Project

    Unity的A*寻路是很常用的功能,比如LOL里面的鼠标点击行走,那么一般情况下做这个导航寻路系统的时候会用两种方式去完成,第一种就是Unity里面自带的NavMeshAgent,第二种就是在Unit ...

  3. 如何制作RTS游戏的寻路系统?

    原文链接:https://blog.uwa4d.com/archives/TechSharing_107.html 这是第107篇UWA技术知识分享的推送.今天我们继续为大家精选了若干和开发.优化相关 ...

  4. unity 游戏中的寻路与导航系统(5种寻路算法详解)

    @了解游戏中常见的寻路方式 通常来讲一般是根据建模方式来决定寻路方式 常见的寻路方式--建模方式 这里提供一下三种建模方式的示意图,如下 ,分别对应着,原图.Grid.WayPoint.NavMesh ...

  5. 2d unity 多物体 射线_24小时入门Unity游戏开发系列教程

    版权声明: 本系列教程来自Unity Game Development in 24 Hours, Sams Teach Yourself(出版日期:2013年12月6日) 教程内容仅供个人学习参考,版 ...

  6. Unity游戏动画 从入门到住院:动画状态机

    好了,现在我们已经成功的导入了动画.接下来要玩的东西就很装13啦.因为大部分动画师是用不到这家伙的,需要掌握这个技能的,至少也是动画组长级别了.嗯...一个组只有你一个动画的,闭嘴!给你个同情的眼神. ...

  7. Unity游戏动画 从入门到住院 4:动画状态机

    Unity游戏动画 从入门到住院:动画状态机 发布者: wuye | 发布时间: 2016-9-7 15:02| 评论数: 3 文/拉撒路 上次我们讲过Unity游戏动画从入门到住院,今天我们来讲一下 ...

  8. unity游戏动画 从入门到住院 二 模型导入

    第一篇:unity游戏动画 从入门到住院 一 导出设置 好的,现在我们已经导出了一个干净或者不干净的FBX,总之他是可用的.至于导出如何设置请看前文链接--既然导出来了我们如何在unity中使用它呢? ...

  9. unity 编辑器存档_Unity教程 | 自制简易的游戏存档系统

    原标题:Unity教程 | 自制简易的游戏存档系统 本文将为大家分享如何在Unity中实现简单的游戏存档系统,其中不会包含太多实际的代码,仅介绍在制作过程中需要考虑与解决的问题.该系统由一个学生团队为 ...

最新文章

  1. Python sorted
  2. 实现不同vlan间PC不可互访,而不同vlan的PC均可访问服务器的特殊效果,(华为)...
  3. cass3d基础版_v1.1_仪表不凡说表:N厂“一劳永逸”V11版实至名归!
  4. CentOS 6.5系统安装配置图解教程(详细图文)
  5. JavaScript 中的string 方法
  6. JavaScript程序开发(十四)—函数声明与函数表达式
  7. JQuery模拟boostrap模态框效果
  8. P3175 [HAOI2015]按位或
  9. 常用的hooks入门
  10. websphere mq 查看队列中是否有数据_如果面试官再问你消息队列,就把这篇甩给他!...
  11. OwnCloud 搭建
  12. 人工智能对计算机技术的,人工智能技术在计算机网络技术的影响
  13. 关于wineQQ8.9.19983deepin23版本提升不能在使用请升级,Linux偷懒升级方法
  14. 软件测试用例设计方法等价划分法
  15. 阿里巴巴Java开发手册(原文地址)
  16. Linux京东签到教程,京东POP店铺签到有礼操作指南
  17. 关于 Spring 中 getBean 的全流程源码解析
  18. 使用CNN实现C-MAPSS数据集里面的剩余寿命预测(Pytorch)
  19. Ubuntu 安装 QEMU
  20. 字节架构师:来说说 Kafka 的消费者客户端详解,你都搞懂了吗?

热门文章

  1. [附源码]java毕业设计毕业生离校管理系统
  2. 如何进入BAT等IT名企
  3. 如何把一张照片的像素提高_教你三个将低分辨率图片放大放清晰的方法
  4. 千万下载量开源软件托管给陌生人 植入恶意代码窃取用户密币
  5. 1228: 9002 Niven数
  6. 网易云的招股书,递交了几分情怀?
  7. 赵艺海个人项目(任务1):猜数字游戏
  8. web 认证服务器简介
  9. ssl数字证书配置(服务器配置、腾讯云配置)
  10. skynet 框架snax源码分析----变量注入