{"id":14277,"url":"\/distributions\/14277\/click?bit=1&hash=17ce698c744183890278e5e72fb5473eaa8dd0a28fac1d357bd91d8537b18c22","title":"\u041e\u0446\u0438\u0444\u0440\u043e\u0432\u0430\u0442\u044c \u043b\u0438\u0442\u0440\u044b \u0431\u0435\u043d\u0437\u0438\u043d\u0430 \u0438\u043b\u0438 \u0437\u043e\u043b\u043e\u0442\u044b\u0435 \u0443\u043a\u0440\u0430\u0448\u0435\u043d\u0438\u044f","buttonText":"\u041a\u0430\u043a?","imageUuid":"771ad34a-9f50-5b0b-bc84-204d36a20025"}

NavMesh в Unity - в чем польза?

Начнем с того что разберемся с тем что такое NavMesh в Unity и как он применяется при навигации ИИ. NavMesh является очень удобным инструментом, а точнее даже комплексом инструментов, которые обеспечивают навигацию и все что связано с ней для неигровых персонажей в игре. Сам NavMesh (или навигационная сетка) представляет собой, как ни странно, трехмерную сетку, наподобие обычного меша, по которой могут перемещаться, так называемые агенты. Эта сетка используется для определения проходимых областей и путей в игровом мире, что обеспечивает интеллектуальное перемещение персонажей в игровой среде. NavMesh позволяет программно управлять движением объектов, обходить препятствия и находить оптимальные пути. Unity и другие игровые движки часто предоставляют инструменты для создания и управления навигационной сетью, что упрощает процесс разработки и оптимизации игрового поведения.

Конечно, в целом, можно было бы обойтись и без NavMesh, существуют различные подходы к реализации поиска пути, самый известный из них, пожалуй — А*, но когда в руках есть уже готовый, удобный инструментарий, это здорово упрощает задачу.

Импорт

Для того чтобы в вашем проекте стал доступен функционал, о котором пойдет речь дальше, вам необходимо установить соответствующий пакедж из PackageManager.

  • Перейдите в Window => PackageManager
  • В открывшемся окне установите фильтр Packages на Unity Registry
  • В отобразившемся внизу списке найдите AI Navigation (если не можете найти, воспользуйтесь поисковой строкой в правом верхнем углу окна)
  • Выбрав этот пакедж, в правой части окна отобразится его страничка, на ней будет кнопка install, нажмите на нее и процесс установки всех необходимых компонентов в ваш проект, будет запущен

ВАЖНО: все приведенные шаги выполнены на версии Unity 2022.3.14.f1, если ваша версия кардинально отличается, возможно какие-то шаги могут не совпадать.

Создание базового навигационного меша

После импорта мы готовы приступить к созданию самой навигационной сетки.

  1. Для этого для начала необходимо создать какой-то объект, на котором будет запечена сетка. Я создал этот пол с использованием ProBuilder, но также подойдет просто обычный деформированный куб или любой другой меш, на ваше усмотрение.

Я создал этот пол с использованием ProBuilder, но также подойдет просто обычный деформированный куб или любой другой меш, на ваше усмотрение.

2. Теперь где-то в иерархии сцены, можно даже на этом объекте, необходимо добавить компонент NavMeshSurface, он отвечает непосредственно за создание навигационной сетки.

3. Теперь нужно лишь нажать на кнопку Bake и навигационная сетка, пусть и с дефолтными настройками, будет создана. На своем объекте вы увидите голубую сетку, это и есть NavMesh.

Различные настройки и решение проблем

В центре моего пола, находится игровой персонаж. По умолчанию при запекании навмеша, он также учитывается, что при стандартных настройках приводит к вот таким артефактам — дырам в навмеше.

Чтобы этого избежать есть несколько вариантов.

1. Первый и самый простой: сменить режим использования геометрии (Use Geometry) в компоненте NavMeshSurface c Render Meshes, что означает, что он будет запечен именно по Renderer’ам, на Physics Colliders, тогда навмеш будет запекаться именно по коллайдерам, что даст более корректный

Но тогда, в случае, если на персонаже есть коллайдер, он будет воспринят системой, как столб. И будет вырезан из навмеша. Это нам тоже не подходит.

2. Здесь мы подходим к второму варианту. Исключение игровых слоев. Я вынес персонажа на отдельный слой. Теперь я могу исключить его из Include Layers в NavmeshSurface, просто сняв с него галочку в раскрывающемся списке.

Таким образом персонаж не будет учтен при запекании навмеша и будет находиться как-бы на нем. Также можно реализовывать какие-то кусты или прочие проходимые объекты на уровне.

Стены и NavMeshModifier

Теперь поговорим о том как нам быть со стенами. Допустим они есть в нашей игре. Если мы просто запечем навмеш со стенами, то он пропечется и на стенах. В некоторых случаях, конечно, это может быть то что надо, но что делать, если мы хотим, чтобы его там не было?

Ну тут, опять же у нас есть несколько вариантов.

  • Первый и самый простой: слегка увеличить радиуса агента для конкретного навмеша. Агент, в данном контексте, это представляемый тип объекта, который будет передвигаться по навмешу. У него есть ряд своих настроек, в том числе радиус. И если этот радиус будет больше, чем какой-то условный дверной проем, то сетка в этом проеме создана не будет, так как наш воображаемый агент не сможет туда протиснуться.

а) В компоненте NavMeshSurface, есть вкладка Agent Type, через нее мы можем попасть в интересующее нас меню настроек агента.

б) В открывшемся окне представлен ряд настроек агента, которые будут учтены при запекании.

среди прочего, есть много всего, но хотелось бы выделить несколько пунктов:

  • Step Height — определяет высоту ступени, на которую может забраться наш агент. Чем этот параметр выше, тем большие перепады высот на навмеше будут сглажены. Этот параметр не может быть больше, чем Height самого агента, если нам нужно выставить очень высокое значение для Step Height, Height также необходимо поднять.
  • Max Slope — определяет угол горки, на которую сможет забраться агент.
  • Radius — то зачем мы сюда вообще пришли, определяет ширину нашего агента.

Немного увеличив радиус перезапечем наш навмеш. Такой вариант отлично подходит, если стены толстые и радиус надо увеличить только немного, но если мы увеличим его слишком сильно, то навмеши пропадут в узких проходах

  • И здесь мы изящно подходим ко второму методу решения проблемы навмеша на стенах, или любых других местах, где его быть не должно. NavMeshModifier. Это компонент, который позволяет нам уточнять, где стоит генерировать навмеш, а где не стоит.

Этот компонент необходимо добавить к каждой стене. После этого Добавить такой же компонент на родительский объект, в котором лежат стены. В случае если в этом компоненте указана галочка Apply To Children, все его настройки автоматически будут применены ко всем вложенным объектам с таким же компонентом

Далее необходимо выбрать галочку Override Area, и в появившемся раскрывающемся списке Area Type, указать пункт Not Walkable, это значит, что по этому объекту нельзя будет ходить

  • Area — это зона, у нас есть возможность создавать кастомные зоны.
  • Для этого в этом же выпадающем списке, внизу можно перейти в Area Settings
  • Перейдя в нее мы увидим строчки, в которых можно создавать свои зоны

У каждой зоны есть имя и цена. Что такое цена? Это по сути приоритетность зоны по которой пойдет агент. То есть чем выше цена, тем меньше вероятность что агент построит себе маршрут через эту зону, если возможность через нее не идти. Например можно создать зону — ядовитое болото, которое будет замедлять и отравлять всех кто в него заходит, назначить ему высокую цену и наши агенты автоматически будут стараться ее обойти,если есть такая возможность.

После этого перезапечь навмеш, и убедиться в том что на стенах он больше не пропекается

Также если мы хотим по каким-то причинам просто вырезать какой-то кусок из навмеша, можно воспользоваться похожим компонентом NavMeshModifierVolume

Он обладает схожим функционалом, с той лишь разницей, что не привязывается ни к мешу, ни к коллайдеру. Вместо этого обладает собственными настройками объема, подобно box collider.

NavMesh агенты

Теперь поговорим о том кто перемещается непосредственно по навмшеу — агентах. Как правило это npc, хотя и не обязательно. У них есть несколько своих настроек, а все управление навигацией персонажа из кода происходит через ссылку именно на этот компонент. У компонента NavMeshAgent также есть ряд настроек

  • Speed — определяет максимальную скорость движения данного агента.
  • Angular Speed — определяет скорость поворота данного агента.
  • Acceleration — определяет то насколько быстро агент достигнет своей максимальной скорости движения.
  • Stopping Distance — определяет расстояние на котором агент остановится от цели при ее достижении.
  • Auto Braking — будет ли скорость автоматически снижаться по мере приближения к цели.
  • Radius — ширина агента в физическом мире

Это основные настройки, которые используются наиболее часто.

Теперь нам надо написать какой-то контроллер для нашего агента. Для этого создадим новый скрипт, добавим его к объекту нашего агента и первым делом получим ссылку на сам компонент

Также я закешировал ссылку на основную камеру и написал простой код, который пускает луч из камеры в точку клика мышкой на экране. Подробно на этом коде останавливаться не будем, так как это не наша тема

Теперь внутри этого if, напишем следующий код, который будет искать ближайшую точку на навмеше от нашего клика, это хорошая практика так как мы можем послать агента и за пределы навмеша, и это будет не очень красиво

  • Метод SamplePosition похож на Raycast, но здесь результат выводится в структуру NavMeshHit. Этот метод принимает следующие аргументы, по порядку:
  • Точка от которой мы будем брать ближайшую на навмеше, внашем случае это попадание луча. out в заранее объявленную переменную. Радиус в котором, от точки попадания луча, будет происходить поиск точки на навмеше. На каких зонах навмеша производить поиск, в данном случае я указал все зоны.

Метод SamplePosition, также как и Raycast возвращает bool, поэтому его можно обернуть в if. И если он вернет true, то есть точка на навмеше будет найдена, то мы можем назначить ее в качестве назначения нашему агенту, с помощью метода SetDestination

Теперь после того как мы кликнем мышкой по какой-то точке на нашем навмеше, то агент отправится прямо к нему.

Также хотелось бы упомянуть про аниматор, точнее про то что ему очень удобно передавать в качестве параметра смешивания анимаций передвижения магнитуду velocity нашего агента

NavMesh Obstacle

Последнее из минимального набора знаний по навмешу, это компонент NavMesh Obstacle. Это препятствия, которые агенты будут стараться всячески избегать. Допустим мы хотим чтобы агенты обходили вот этот столб.

Тогда мы добавляем к нему компонент NavMesh Obstacle

Тут также есть некоторые настройки:

  • Shape — это то какой формы будет наше препятствие. На выбор имеется две формы — box и capsule.
  • Center — точка центра препятствия
  • Size — размер сторон препятствия, в случае с capsule тут еще есть высота и радиус

Carve — является одной из самых интересных функций данного компонента. В случае если эта галочка отключена, то агенты будут пытаться исправлять свой маршрут только если уже столкнулись с препятствием.В случае если ее нажать, то появятся несколько дополнительных настроек, а в навмеше под объектом вырежется дыра

  • Теперь если мы будем перемещать наш объект, эта дырка будет автоматически обновляться на навмеше. В эдит моде все происходит мгновенно, а вот для рантайма тут уже есть несколько настроек.
  • Time To Stationary — это параметр, который определяет через сколько секунд, после перемещения объекта, навмеш будет обновлен с учетом его новой позиции.Carve Only Stationary — галочка отвечающая за то будет ли вырезаться из навмеша данный обстакл только когда он неподвижен или же всегда. По умолчанию она включена, но если ее отключить объект будет вырезаться из навмеша постоянно. Таким образом удобно реализовывать движущиеся препятствие, но это достаточно требовательная операция, так что с ней надо быть аккуратнее.Move Threshold — параметр определяющий расстояние, на которое необходимо сдвинуть объект от его изначальной позиции, чтобы навмеш обновился. Таким образом увеличив этот параметр можно частично компенсировать отключенную галочку Carve Only Stationary.

Теоретически NavMesh Obstacle можно использовать для исключения стен из навмеша, но лучше использовать именно NavMesh Modifier, так как он является менее требовательным.

Заключение

Это основные знания необходимые для старта в навигации по средствам NavMesh. Конечно это далеко не все что можно рассказать по этому теме, но я уверен что в будущем мы еще вернемся к этому вопросу. Есть еще jump, link, много разнообразных методов и куча всего интересного. Но пока что на этом остановимся. Спасибо за уделенное, на прочтение, время и до новых встреч!

0
Комментарии
-3 комментариев
Раскрывать всегда