【问题标题】:C# Set Rotation of Object to Face CoordinatesC# 将对象的旋转设置为面坐标
【发布时间】:2020-12-15 20:30:58
【问题描述】:

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

我有一个大网格和两个对象的 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);

这似乎工作正常。然后我需要旋转玩家面对目的地并让他们朝着目的地移动直到距离X/Y

编辑:我一直在搞乱 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。

【问题讨论】:

  • 我看到你交换了Atan2函数的参数,y向量应该是第一个参数,x向量应该是第二个。
  • 你得到的角度可能是逆时针的,所以也要记住这一点
  • 哦,哎呀!我把它换成了:double theta = Math.Atan2((targetCoords.yValue - playerCoords.yValue), (targetCoords.xValue - playerCoords.xValue)); 但我的结果仍然是错误的。有时大于 360 或小于 0。是因为它是逆时针的吗?我将如何解决这个问题?
  • 我不太确定 double 到 int 的转换。将“theta = theta * (180 / Math.PI)”替换为“theta = theta * (180.0 / Math.PI)”只是为了保存。 (注意 180 之后的 .0)并且你得到的 Atan2 角度已经是玩家应该看到的角度。因此,您可以删除该 sigma omega 计算。你要找的角度是theta,在输出日志中看一下
  • 似乎仍然不起作用。玩家:(4782, 4172) 目标:(4749, 4157) 角度应该在 74~ 左右。但是 Theta = -155 和 omega = 229。

标签: c# rotation grid coordinates


【解决方案1】:

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

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

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

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

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

现在要获得角度,您可以使用: 双角 = 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
    // https://stackoverflow.com/a/25725005/7671671
    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
}

【讨论】:

  • 这非常有用,让我从事了很多富有成效的工作。但我仍然不完全在那里。用我更新的作品更新我的原始帖子。
  • 对不起,我很困惑。所以你是说 Atan2 返回一个基于 0 度(弧度?)在 3 点钟位置的结果?然后它逆时针移动?但是你说你在下面的代码中做了错误的假设。我现在有点迷路了。
  • 像我一样将 atan2 转换为度数后,它在 3 点钟从 0 度开始,然后逆时针移动
  • 那么如果我的玩家当前的轮换是从 12 点开始计算并逆时针旋转...我只需要使用我已有的公式和 atan2 结果中的 -90?
  • 是的,但你不应该这样做,因为它会混淆其他开发人员。见here
猜你喜欢
  • 1970-01-01
  • 2019-05-08
  • 2019-03-21
  • 2021-09-15
  • 2016-06-11
  • 1970-01-01
  • 1970-01-01
  • 2015-06-18
  • 2021-06-06
相关资源
最近更新 更多