Дополнение к руководству по использованию NavMesh в Unity

NavMesh Unity

Предыдущая статья про NavMesh в unity для начинающих

Читать: Как использовать NavMesh в Unity: руководство для начинающих

1. Работа с несколькими зонами NavMesh

В сложных сценах может потребоваться разделить NavMesh в unity на несколько зон, чтобы агенты могли перемещаться между ними. Например, в игре с открытым миром можно разделить карту на регионы, каждый из которых имеет свой NavMesh.

Как настроить несколько зон NavMesh:

  1. Создайте несколько NavMesh Surface:
    Добавьте на сцену несколько объектов (например, Plane или Terrain), которые будут представлять разные зоны.
    Для каждого объекта добавьте компонент NavMesh Surface.
    Настройте параметры каждой поверхности (Agent Radius, Agent Height, Include Layers).
  2. Свяжите зоны с помощью OffMesh Links:
    Используйте OffMesh Links для соединения зон, если они не соединены физически (например, между этажами здания).

Пример скрипта для переключения между зонами: csharp 

UnityEngine;
using UnityEngine.AI;

public class MultiZoneNavigation : MonoBehaviour
{
public NavMeshSurface[] surfaces;
private NavMeshAgent agent;

void Start()
{
agent = GetComponent<NavMeshAgent>();
BakeAllSurfaces();
}

void BakeAllSurfaces()
{
foreach (var surface in surfaces)
{
surface.BuildNavMesh();
}
}

public void MoveToZone(Vector3 targetPosition)
{
agent.SetDestination(targetPosition);
}
}

Этот скрипт позволяет агенту перемещаться между несколькими зонами NavMesh.

2. Использование NavMesh Areas

NavMesh Areas позволяют задавать разные типы поверхностей, например, земля, вода, грязь, и настраивать стоимость прохода для каждого типа.

Как настроить NavMesh Areas:

  1. Создайте новые области:
    Откройте меню Window > AI > Navigation.
    Перейдите на вкладку Areas.
    Создайте новые области (например, “Ground”, “Water”, “Mud”).
  2. Назначьте области объектам:
    Выберите объект (например, Plane).
    В Inspector найдите компонент NavMesh Surface.
    В разделе Default Area выберите нужную область.
  3. Настройка стоимости прохода:
    В меню Navigation на вкладке Areas задайте стоимость прохода для каждой области.
    Например, для “Water” можно установить стоимость 10, чтобы агенты избегали воды.
  4. Пример использования:
    Создайте зону с типом “Water” и назначьте ей высокую стоимость прохода. Агенты будут избегать этой зоны, если есть альтернативный путь.

3. Настройка агентов для разных типов поверхностей

В некоторых играх агенты могут иметь разные характеристики в зависимости от поверхности, по которой они перемещаются. Например, персонаж может двигаться медленнее по грязи.

Как настроить поведение агентов:

  1. Используйте NavMesh Areas:
    Назначьте разные области для разных типов поверхностей.

Напишите скрипт для изменения скорости агента: csharp

UnityEngine;
using UnityEngine.AI;

public class AdaptiveAgent : MonoBehaviour
{
private NavMeshAgent agent;
private float baseSpeed;

void Start()
{
agent = GetComponent<NavMeshAgent>();
baseSpeed = agent.speed;
}

void Update()
{
NavMeshHit hit;
if (agent.SamplePathPosition(NavMesh.AllAreas, 0.0f, out hit))
{
switch (hit.mask)
{
case 1: // Ground
agent.speed = baseSpeed;
break;
case 2: // Water
agent.speed = baseSpeed * 0.5f;
break;
case 3: // Mud
agent.speed = baseSpeed * 0.3f;
break;
}
}
}
}
Этот скрипт изменяет скорость агента в зависимости от типа поверхности.

4. Динамические препятствия

Настройка динамического препятствия

  1. Выберите объект, который будет двигаться (например, движущаяся платформа).
  2. В Inspector добавьте компонент NavMesh Obstacle.
  3. Включите опцию Carve, чтобы препятствие “вырезало” область из NavMesh при движении.

Пример скрипта для движения препятствия: csharp

using UnityEngine;

public class MovingObstacle : MonoBehaviour
{
public Vector3[] waypoints;
public float speed = 2.0f;
private int currentWaypoint = 0;

void Update()
{
if (waypoints.Length == 0) return;

transform.position = Vector3.MoveTowards(transform.position, waypoints[currentWaypoint], speed * Time.deltaTime);

if (Vector3.Distance(transform.position, waypoints[currentWaypoint]) < 0.1f)
{
currentWaypoint = (currentWaypoint + 1) % waypoints.Length;
}
}
}

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

5. Интеграция с анимацией

Для создания реалистичного поведения персонажей важно синхронизировать движение агента с анимацией.

Настройка анимации

  1. В аниматоре создайте параметры, такие как Speed и Direction.

Скрипт для управления анимацией: csharp

using UnityEngine;
using UnityEngine.AI;

public class AnimatedAgent : MonoBehaviour
{
private NavMeshAgent agent;
private Animator animator;

void Start()
{
agent = GetComponent<NavMeshAgent>();
animator = GetComponent<Animator>();
}

void Update()
{
animator.SetFloat("Speed", agent.velocity.magnitude);
animator.SetFloat("Direction", Vector3.Dot(agent.velocity.normalized, transform.forward));
}
}

Этот скрипт синхронизирует движение агента с анимацией.

Пример: Создание сложного AI с использованием NavMesh

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

  1. Создайте точки патрулирования:
    Добавьте на сцену несколько объектов (например, Empty GameObjects) и расставьте их в нужных местах.

Напишите скрипт для сложного поведения: csharp

using UnityEngine;
using UnityEngine.AI;

public class AdvancedAI : MonoBehaviour
{
public Transform[] patrolPoints;
public Transform player;
public float detectionRange = 10.0f;
public float chaseRange = 20.0f;

private NavMeshAgent agent;
private int currentPoint = 0;
private bool isChasing = false;

void Start()
{
agent = GetComponent<NavMeshAgent>();
MoveToNextPoint();
}

void Update()
{
float distanceToPlayer = Vector3.Distance(transform.position, player.position);

if (distanceToPlayer < detectionRange)
{
isChasing = true;
}
else if (distanceToPlayer > chaseRange)
{
isChasing = false;
MoveToNextPoint();
}

if (isChasing)
{
agent.SetDestination(player.position);
}
else if (!agent.pathPending && agent.remainingDistance < 0.5f)
{
MoveToNextPoint();
}
}

void MoveToNextPoint()
{
if (patrolPoints.Length == 0) return;
agent.SetDestination(patrolPoints[currentPoint].position);
currentPoint = (currentPoint + 1) % patrolPoints.Length;
}
}
// Этот скрипт заставляет NPC патрулировать территорию и преследовать игрока при обнаружении.

Подписывайтесь на телеграм о разработке игр: HAKSTER

Мой дзен: HAKSTER Games | HSG