如何逐渐旋转一个物体以面对另一个物体转动最短距离

发布于 2024-12-11 13:14:34 字数 1039 浏览 0 评论 0 原文

我目前正在尝试旋转精灵,具体取决于它与直接面向目标的角度(或拉德,我更喜欢度数)不同,问题是当目标到达某个位置时,精灵决定旋转完整的 360 度采取其他方式,而不是多做 10 件事。这张图片可能更好地解释了这个问题:

蓝色方块 = 目标

红色方块 = 对象

绿线 = 它想要的旋转

黑线 = 当前旋转

棕色箭头 = 如何旋转它旋转以实现这个

红色箭头=我想要的旋转。

请注意,情况 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:对于标题的建议也将不胜感激,因为我完全不知道该放什么。

I'm currently trying to rotate a sprite depending on how many degrees(or rads, I prefer degrees) it differs from facing straight towards a target, the problem is when the target reaches a certain position the sprites decides to do rotate a full 360 to other way instead of doing the 10 extra. This picture probably explains the problem better:

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.

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.

Note that Case 1 always work, depending what way it rotates, but Case 2 it always does that rotation, no matter if it is to the "right" or "left" of the current rotation.

This is the code I'm using to rotate the object.

    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;

What i want to achieve is have it rotate (in Case 2) according to the red arrow instead of the brown one.

NOTE: I'm not an expert at programming, I've only done it from time to time for the past year(Mainly simple 2D Shooter/shoot'em up kind of games), so in depth explanation would be appreciated. I'm also a student learning programming.

PS: Suggestions for Title would also be appreciated as I had absolutely no idea what to put there.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

凑诗 2024-12-18 13:14:34

您的问题是目标可能处于角度 5,而物体可能面向 355 度(例如)。根据你的测试,5小于355,所以逆时针走。

你应该做的是测试目标是否在你左边180度以内,或者在你右边180度以内,然后相应地移动。

棘手的部分是让支票在 360° 左右“环绕”。 0.看起来你的情况下还剩下0度,所以硬测试是当wantRot位于其中有0度的一侧时。

为了形象地画一个圆圈,如下所示,然后将您的物体放在我们面对的左侧。您会发现必须分别检查 2 个阴影区域。

Visualization

方法 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;
}

Your problem is that the target could be at angle 5, and the object could be facing 355 degrees (for example). According to your test, 5 is less than 355, so go anticlockwise.

What you should do is test whether the target is within 180 degrees to your left, or within 180 degrees to your right, then move accordingly.

The tricky part is getting the check to 'wrap' around 360 <-> 0. It looks like 0 degrees is left in your case, so the hard test is for when the wantRot is on the side that has 0 degrees within it.

To visualise draw a circle as below, then place your object on the left of where we're facing. You'll see that you have to check the 2 shaded areas separately.

Visualisation

Method 1

Check all cases separately.

Note: Code below is in my head and untested. You'll need to change degrees to radians.

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;
}

Method 2

From looking at the image, you may realise that you could just check whether the object on the right, then if not, assume it's on the left (since as long as the current angle is less than 180 degrees checking its on the right is easy). If the current angle is more than 180 degrees, then reverse the concept - check whether it's on the left and if not assume right. Something like below:

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文