Как повернуть NavMeshAgent в направлении движения?

Я работаю над 2D-игрой в плоскости XY. Я создал врагов с помощью NavMeshAgent и дал своим агентам возможность перемещаться между ними. Проблема в том, что я не знаю, как вращать их в направлении движения или векторе скорости (синяя стрелка). Передняя часть агента находится в направлении оси Y (зеленая стрелка). Обратите внимание, что updateRotation не является опцией. Он повернет агент и заставит его исчезнуть (агент вращается на 90 градусов вокруг оси X).

вот код, который я нашел на форуме Unity, он отлично работает в 3D, но я не могу заставить его работать в 2D

    void FaceTarget()
    {
        Vector3 direction = agent.steeringTarget;
        Quaternion lookRotation = Quaternion.LookRotation(new Vector3(direction.x, 0, direction.z));
        transform.rotation = Quaternion.Slerp(transform.rotation, lookRotation, Time.deltaTime * 5);
    }

Я попробовал этот код. Он вычисляет угол между вектором скорости и локальной осью Y. Желаемый результат: агент вращается в направлении своего движения. На самом деле агент вращается, но в некоторых моментах он не в направлении движения. Я знаю, что проблема в том, что диапазон ангелов составляет [0,180], а не [0,360], но я не могу найти для этого решения.

    void FaceTarget()
    {
        Vector3 lookTarget = agent.velocity.normalized;
        float angel = Vector3.Angle(lookTarget, Vector3.up);
        transform.rotation = Quaternion.Euler(0,0,angel);
    }
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
55
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

ОБНОВЛЕНИЕ: Изменено для работы с 2D-плоскостью x-y, в то время как оригинал был 2-мерной плоскостью в 3d-x-z.

SteeringTarget не эквивалентен вектору направления. Это положение целевого вектора, к которому нужно добраться. Желаемое направление больше похоже на SteeringTarget — текущую позицию агента.

Фактическое направление движения можно получить из Agent.velocity.

Ваш код выше можно изменить на:

void FaceTarget()
{
    Vector3 direction = agent.velocity;
    Quaternion lookRotation = Quaternion.LookRotation(new Vector3(direction.x, direction.y, 0));
    transform.rotation = Quaternion.Slerp(transform.rotation, lookRotation, Time.deltaTime * 5);
}

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

void FaceTarget()
{
    if (agent.velocity.magnitude > MINIMUM_SPEED)
    {
        Vector3 direction = agent.velocity;
        Quaternion lookRotation = Quaternion.LookRotation(new Vector3(direction.x, direction.y, 0));
        transform.rotation = Quaternion.Slerp(transform.rotation, lookRotation, Time.deltaTime * 5);
    }
}

Наконец, если у вас возникнут какие-либо проблемы, рассмотрите возможность поворота подобъекта, предназначенного только для визуальных эффектов, вместо основного преобразования.

Для низких скоростей я обычно использую .Normalized, чтобы получить направление вектора. Я попробовал код, который вы предоставили. Он вращает поверхность агентов в направлении вектора скорости. Другая проблема заключается в том, что при остановке агента все возвращается в нормальное состояние. Я имею в виду, что агент возвращается к ротации (0,0,0). Методы кватернионов, которые обычно используются в 3D, в этом случае не могут быть использованы. Все они используют ось Z в качестве прямого вектора.

A-Eye 14.09.2023 20:49

Quaternion.LookRotation неявно использует Vector3.up (0,1,0) в качестве вектора вверх, который работает в трехмерном пространстве. Попробуйте использовать Vector3.forward (0,0,1) или Vector3.back (0,0,-1) в качестве вектора вверх и посмотрите, что получится. Это должно привести к вращению во 2d горизонтальной плоскости. Это может выглядеть так: Quaternion.LookRotation(new Vector3(direction.x, Direction.y, 0), Vector3.forward);

Joe Spiro 14.09.2023 21:03

Спасибо за ответ, мне очень помогло🙏

A-Eye 14.09.2023 22:16
Ответ принят как подходящий

Я решил это с помощью Вот код

void FaceTarget()
{
    if (agent.velocity != Vector3.zero)
    {
        Vector3 moveDirection = new Vector3(agent.velocity.x, agent.velocity.y, 0f);
        if (moveDirection != Vector3.zero)
        {
            float angel = Mathf.Atan2(moveDirection.x, moveDirection.y) * Mathf.Rad2Deg;
            transform.rotation = Quaternion.AngleAxis(angel, Vector3.back);
        }
    }

}

Вот еще один код, предоставленный @DMGregory

void FaceTarget() {
    var vel = agent.velocity;
    vel.z = 0;

    if (vel != Vector3.zero)
    {
        transform.rotation = Quaternion.LookRotation(Vector3.forward, vel);
    }
}

Другие вопросы по теме