C# 设置物体旋转到面坐标

C# Set Rotation of Object to Face Coordinates

我正在使用 C# 在自定义引擎中制作游戏。 (不是 Unity)

我有一个大网格和两个对象的 x/y 坐标。 Player 对象和 Destination 对象。以及玩家当前的旋转度数 (0-360)。

我已经变得过于依赖现有的游戏引擎,并且不知道如何找到我需要让玩家面对目标的旋转。

playerRotation;//0 to 360 degrees.
playerX double = 47.43;
playerY double = 43.36;
targetX double = 52.15;
targetY double = 38.67;

我目前的方法是尝试通过以下方式获取对象之间的距离:

float distanceX = Math.Abs(playerX - destinationX);
float distanceY = Math.Abs(playerY - destinationY);

这似乎工作正常。然后我需要旋转玩家面对目的地并让他们朝目的地移动,直到 distanceX/Y <= 0.

编辑:我一直在和 Atan2 打交道,试图找到答案。

Vector2 playerCoords = new Vector2(playerX, playerY);
Vector2 targetCoords = new Vector2(targetX, targetY);

double theta = Math.Atan2((targetCoords.yValue - playerCoords.yValue), (targetCoords.xValue - playerCoords.xValue));

theta = theta * (180 / Math.PI);//Convert theta to degrees.

double sigma = playerRotation;//Direction in degrees the player is currently facing.

double omega = sigma - theta;

OutputLog("omega: " + omega);

我的输出日志应该显示我的玩家需要面向目标的度数。但它给了我错误的结果。

玩家:(4782, 4172) 和 目标:(4749, 4157)

角度应该是286左右~。

但是 Theta = -155 和 omega = 229。

矢量数学很有用,而且没那么复杂。

第一个向量是你的玩家位置和目的地:

Vector2 playerPos = new Vector2(playerX, playerY);
Vector2 destinationPos = new Vector2(destinationX, destinationY);

现在你可以只减去两个向量,得到一个从一个位置指向另一个位置的向量。

Vector2 delta = destination - playerPos; // Note, it might be the other way around: playerPos - destination

那个增量向量有一个长度,那就是两点之间的距离。 Vector class 上通常有一个 Length 和一个 LengthSquared 属性。但是请注意,计算长度相当 CPU 密集,因为它使用平方根。如果您想将该距离与固定距离(如 200)进行比较,只需使用长度的平方并将其与更快的方式 (200 * 200) 进行比较。

您也可以使用该增量,让子弹从一个位置飞到另一个位置。你只需要规范化增量,有一种方法,你可以将它缩小到长度一。您现在可以使用该增量乘以每个物理循环的速度来更改子弹位置。

现在要获取角度,您可以使用: 双角 = Math.Atan2 (delta.Y, delta.X); // 注意这里y和x是颠倒的,应该是这样的。

请注意,这个角度的单位是弧度,而不是度数。弧度圆从 -PI 开始,到 PI 结束。因此,一个完整的圆是 2 * PI。把弧度换算成度数,可以看this question

编辑

我一直假设12点是0度,3点是90度,6点是180度,9点是270度。

但实际上在笛卡尔坐标系中情况有点不同。我也在下面的代码中做出了这个错误的假设。

但事实证明我错了。看这张照片

现在,如果您查看我的源代码,我所有的变量都被错误地命名了。但是,如果您查看它们的值,您会发现它们与图片相符。因此,Atan2 修正是它应该的样子。 // 使用来自 System.Numerics;

的 Vector2
internal static double RadianToDegree(double rad)
{
    double thetaDegree = rad * (180.0 / Math.PI);

    // Convert negative angles into positive ones
    // 
    double thetaDegree2 = (thetaDegree + 360) % 360;

    return thetaDegree2;
}

internal void Run()
{
    // Player: (4782, 4172) and Target: (4749, 4157)

    Vector2 player = new Vector2(4782, 4172);
    Vector2 target = new Vector2(4749, 4157);

    Vector2 delta = target - player;

    double theta = Math.Atan2(delta.Y, delta.X);
    double thetaDegree = RadianToDegree(theta);

    // Given cartesian coordinate system
    // positive y is up, negative is down
    // positive x is right, negative is left

    // Falsely assuming up is 0
    // Falsely assuming right is 90
    // Falsely assuming down is 180
    // Falsely assuming left is 270
    Vector2 v0 = new Vector2(0, 1);
    Vector2 v45 = new Vector2(0.5f, 0.5f);
    Vector2 v90 = new Vector2(0.5f, 0);
    Vector2 v180 = new Vector2(0, -1);
    Vector2 v270 = new Vector2(-1, 0);

    double theta0 = Math.Atan2(v0.Y, v0.X);
    double theta45 = Math.Atan2(v45.Y, v45.X);
    double theta90 = Math.Atan2(v90.Y, v90.X);
    double theta180 = Math.Atan2(v180.Y, v180.X);
    double theta270 = Math.Atan2(v270.Y, v270.X);

    double result0 = RadianToDegree(theta0);
    double result45 = RadianToDegree(theta45);
    double resultv90 = RadianToDegree(theta90);
    double resultv180 = RadianToDegree(theta180);
    double resultv270 = RadianToDegree(theta270);

    // result 0 --> 90
    // result 45 --> 45
    // result 90 --> 0
    // result 180 --> 270
    // result 270 --> 180
}