reckfellENGINE

Агент навигации: движение, состояния и избегание

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

На этой странице

NavigationAgent2D помогает родительской Entity выбирать точки пути и рассчитывать избегание. Он не перемещает родителя и не заменяет физическое тело. В 3D используется NavigationAgent3D; законченный выполненный пример ниже — движение сверху в 2D, без гравитации.

Настроить персонажа 2D

Нужен C#-проект Reckfell 1.0.0 с готовой навигационной картой. Создайте CharacterBody2D, добавьте CollisionShape2D с кругом радиуса 0,25 и дочерний NavigationAgent2D с точным именем NavigationAgent2D. Прикрепите к телу NavigationWalker2D.cs:

C#
using Reckfell;

public partial class NavigationWalker2D : CharacterBody2D
{
    [Export] public float Speed { get; set; } = 8;
    public NavigationAgent2D Agent { get; private set; } = null!;

    public override void _Ready()
    {
        Agent = GetEntity<NavigationAgent2D>("NavigationAgent2D");
        Agent.PathDesiredDistance = 0.25f;
        Agent.TargetDesiredDistance = 0.25f;
        Agent.Radius = 0.25f;
        Agent.MaxSpeed = Speed;
        Agent.VelocityComputed += ApplyVelocity;
    }

    public void SetDestination(Vector2 target) => Agent.TargetPosition = target;

    public override void _PhysicsProcess(double delta)
    {
        if (NavigationServer2D.MapGetIterationId(Agent.GetNavigationMap()) == 0
            || Agent.IsNavigationFinished())
        {
            Velocity = Vector2.Zero;
            if (Agent.AvoidanceEnabled) Agent.Velocity = Vector2.Zero;
            return;
        }

        Vector2 next = Agent.GetNextPathPosition();
        Vector2 desired = GlobalPosition.DirectionTo(next) * Speed;
        if (Agent.AvoidanceEnabled) Agent.Velocity = desired;
        else ApplyVelocity(desired);
    }

    private void ApplyVelocity(Vector2 velocity)
    {
        Velocity = velocity;
        MoveAndSlide();
    }

    public override void _ExitTree() => Agent.VelocityComputed -= ApplyVelocity;
}

Speed задаётся положительным числом в единицах карты в секунду; в проверке использовано 8. Если меняете скорость во время игры с избеганием, обновите также Agent.MaxSpeed. Радиус 0,25 выбран под проверочный круг, а не как универсальное значение для пиксельных персонажей.

При отдельной карте вызовите walker.Agent.SetNavigationMap(map). После публикации навигации передайте глобальную цель в walker.SetDestination(target). Не переназначайте ту же цель каждый кадр без необходимости: это сбрасывает маршрут и может вызвать дёрганье.

На прямоугольнике x=0–20, y=0–10 тело со старта (2, 5) дошло до (18, 5) и остановилось. Velocity передаётся в MoveAndSlide() в единицах в секунду: умножать её на delta здесь не нужно. MoveAndSlide() выполняет своё интегрирование шага физики.

Различать состояния

МетодЗначение
GetNextPathPosition()Следующая точка; вызов также обновляет внутреннее состояние агента. Получайте её в цикле физики, пока маршрут не завершён.
IsNavigationFinished()Агент закончил текущий маршрут. Это может быть конец частичного пути.
IsTargetReached()Агент отметил достижение исходной цели с TargetDesiredDistance.
IsTargetReachable()Конец найденного пути достаточно близок к цели; это не гарантия физического прохода тела.
GetFinalPosition()Конец текущего пути, а не обязательно исходная цель.

Цель (30, 5) в проверке оказалась за пределами карты. Агент закончил маршрут у доступной границы: IsNavigationFinished() стал true, IsTargetReached() остался false. Обработайте такой исход отдельно: остановитесь, выберите другую цель или сообщите о недостижимости.

Расстояния PathDesiredDistance и TargetDesiredDistance подбираются под масштаб, скорость и шаг физики. Слишком малый допуск может привести к перескоку точки и движению назад; слишком большой — к преждевременному завершению или срезанию угла. Значения 0,25 проверены только для этой простой геометрии.

Избегание и физика

Без избегания пример передаёт желаемую скорость телу напрямую. При AvoidanceEnabled = true скорость сначала передаётся агенту, а тело двигается из VelocityComputed. Подключение сигнала не требует создания второго низкоуровневого callback поверх Entity агента.

В выполненной проверке callback выдавал конечные значения в пределах MaxSpeed. Это не гарантия обхода любой толпы или узкого прохода. Radius избегания не изменяет запечённый зазор навигационного меша.

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

Диагностика

  • Тело стоит: проверьте карту, публикацию, слои, имя дочернего агента и назначение цели.
  • Движется слишком медленно: не умножайте скорость для MoveAndSlide на delta второй раз.
  • Дёргается у цели: не продолжайте следование после завершения; проверьте допуски и частоту переназначения цели.
  • Упирается в стену: проверьте навигационную геометрию и обработку застревания.

Проверены точный код, физическое движение до цели, остановка, частичный маршрут, блокировка стеной и callback избегания. Толпа, переходы NavigationLink, 3D-движение и производительность не проверены этим набором.

Документация Reckfell EngineНаверх ↑
БЫСТРЫЙ ПЕРЕХОДНачало работыEntity и иерархияC# & .NET 10Сцены и префабы
Руководства и полный API Reckfell K
reckfellENGINE
RECKFELL ACCOUNT

Вход в аккаунт

Войдите в аккаунт Reckfell.

Один аккаунт для всей платформы Reckfell.