Как постепенно повернуть объект лицом к другому повороту на кратчайшее расстояние - PullRequest
13 голосов
/ 21 октября 2011

В настоящее время я пытаюсь повернуть спрайт в зависимости от того, на сколько градусов (или ярдов, я предпочитаю градусы) он отличается от прямого взгляда на цель, проблема в том, что когда цель достигает определенного положения, спрайты решают повернуть полный 360 в другую сторону вместо 10 дополнительных. Эта картина, вероятно, лучше объясняет проблему:

Blue square = target, Red square = the object, green line = rotation it wants, black line = current rotation, brown arrow = how it rotates to achieve this, red arrow = how I want it to rotate.

Синий квадрат = цель

Красный квадрат = объект

Зеленая линия = вращение, которое она хочет

Черная линия = текущее вращение

Коричневая стрелка = как она вращается, чтобы достичь этого

Красная стрелка = как я хочу, чтобы она вращалась.

Обратите внимание, что Случай 1 всегда работает, в зависимости от того, как он вращается, но Случай 2 всегда делает это вращение, независимо от того, находится ли он «вправо» или «влево» от текущего вращения.

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

    Vector2 distance = new Vector2(target.worldPos.X - this.worldPos.X, target.worldPos.Y - this.worldPos.Y);
    float wantRot = (float)Math.Atan2(distance.Y, distance.X);
    if (this.rotation < wantRot)
        this.rotation += MathHelper.ToRadians(45) * Time.deltaTime;
    if (this.rotation > wantRot)
        this.rotation -= MathHelper.ToRadians(45) * Time.deltaTime;

Чего я хочу добиться - это повернуть его (в случае 2) в соответствии с красной стрелкой вместо коричневой.

ПРИМЕЧАНИЕ: я не эксперт в программировании, я делал это время от времени только в течение прошлого года (в основном, это простые 2D-игры в жанре «стрелялки / стрелялки»), так что подробное объяснение приветствуется. , Я также студент, изучающий программирование.

PS: Предложения по названию также приветствуются, так как я понятия не имел, что туда поставить.

1 Ответ

12 голосов
/ 21 октября 2011

Ваша проблема в том, что цель может быть под углом 5, а объект может быть направлен на 355 градусов (например).Согласно вашему тесту, 5 меньше 355. Идите против часовой стрелки.

Что вам нужно сделать, это проверить, находится ли цель в пределах 180 градусов слева или в пределах 180 градусов справа от вас, затем двигайтесь соответствующим образом.

Хитрая часть заставляет чек «обернуть» около 360 <-> 0. Похоже, в вашем случае осталось 0 градусов, поэтому жесткий тест для случая, когда wantRot находится на стороне, которая имеет0 градусов внутри него.

Чтобы визуализировать, нарисуйте круг, как показано ниже, затем поместите ваш объект слева от того места, где мы смотрим.Вы увидите, что вам нужно проверить 2 заштрихованные области отдельно.

Visualisation

Метод 1

Проверить все случаи отдельно.

Примечание: Код ниже у меня в голове и не проверен.Вам нужно будет изменить градусы на радианы.

int MoveDir = 0;
var BehindMe = this.rotation - 180;
if (BehindMe < 0)
    BehindMe += 360;

if (wantRot != this.rotation)
{
    if (wantRot == BehindMe)
        MoveDir = 1; // or randomly choose
    else if ((wantRot > BehindMe && wantRot < this.rotation) ||
             (this.rotation < 180 && (wantRot > BehindMe ||
                                      wantRot < this.rotation)))
        MoveDir = -1;
    else if ((wantRot < BehindMe && wantRot > this.rotation) ||
             (this.rotation > 180 && (wantRot < BehindMe ||
                                      wantRot > this.rotation))
        MoveDir= 1;

    this.rotation += MoveDir * MathHelper.ToRadians(45) * Time.deltaTime;
}

Метод 2

Глядя на изображение, вы можете понять, что можете просто проверить, находится ли объект справа, тогда, если нет, предположим, что он слева (поскольку, пока текущий угол меньше 180 градусов, проверить его справа легко).Если текущий угол больше 180 градусов, поменяйте концепцию - проверьте, находится ли он слева, а если нет, то вправо.Примерно так:

int MoveDir = 0;
var BehindMe = this.rotation - 180;
if (BehindMe < 0)
    BehindMe += 360;

if (wantRot != this.rotation)
{
    if (this.rotation <= 180)
    {
        if (wantRot > this.rotation && wanrRot < BehindMe)
            MoveDir = 1;
        else
            MoveDir = -1;
    }
    else
    {
        if (wantRot < this.rotation && wanrRot > BehindMe)
            MoveDir = -1;
        else
            MoveDir = 1;
    }

    this.rotation += MoveDir * MathHelper.ToRadians(45) * Time.deltaTime;
}
...