确定我的对象在 2D 平面上朝向哪个方向

本文关键字:方向 平面 我的 对象 2D | 更新日期: 2023-09-27 17:56:32

我和我的朋友在XNA 4.0中胡闹,制作2D赛车游戏。有点像这个:伊万"钢铁侠"斯图尔特的超级越野。我们遇到的问题是知道汽车朝哪个方向适当地移动它。我们可以通过枚举值北、南、东、西来跟踪方向,但由于多种原因,我们不想这样做。

我们想知道是否有办法通过数学来实现这一点。也许通过在汽车引擎盖上指定一个锚点,让汽车始终向该位置移动,然后移动该锚点。我们不确定。或者也许有一种方法可以使用 2D 矢量。

我想既然我们遇到了困难,我们应该向编码社区寻求帮助!

只是为了清楚。我不是在找代码;我只想讨论一些 2D 在所有方向上移动的概念,而不必跟踪方向枚举。我知道这不可能是唯一的方法。

确定我的对象在 2D 平面上朝向哪个方向

汽车物理学实际上是一门非常困难的学科。我祝你一切顺利,但你正在开始一个艰难的追求。

至于答案:您可以将方向角存储在弧度中,并使用 atan2 函数获取角度之间的关系。

或者你可以使用Vector2D并使用矢量数学来确定角度,atan2也将是你的朋友。

我关于这个问题的代码片段:

public class RotatingImage implements RotatingImageVO {
  protected double x, y; // center position
  protected double facingx, facingy;
  protected double angle;
  protected void calculateAngle() {
    angle = Math.atan2(x-facingx, facingy-y);
  }
}

请记住,计算 atan2 是昂贵的。当我为每个对象的每次绘制迭代执行此操作时(塔防,塔在旋转;它占用了我~30%的计算能力。仅当您检测到明显的角度变化时才执行此操作。喜欢这个:

public void setFacingPoint(double facingx, double facingy) {
  if (Math.abs((facingx-this.facingx)/(facingx+this.facingx)) > 0.002 
      || Math.abs((facingy-this.facingy)/(facingy+this.facingy)) > 0.002) {
    this.facingx = facingx;
    this.facingy = facingy;
    calculateAngle();
  }
}

您可以使用规范化向量来表示方向。这只是一个硬编码示例,但您可以轻松使用游戏手柄操纵杆的输入。

Vector2 north = new Vector2(0, -1);

稍后在你的代码中像这样移动你的精灵(假设有一个位置向量)。

float speed = 100; // 100 pixels per second.
Vector2 direction = north;
position += direction * ((float)gameTime.ElapsedGameTime.TotalSeconds * speed);

使用单位向量描述方向,使用点描述位置是有意义的。然后当汽车向前移动时,你这样做

currentPosition = currentPosition + distance * directionvector;//(伪代码)

更改方向时,最好使用矩阵来(旋转)变换方向矢量。

(我不熟悉XNA)

编写了一些虚拟代码来说明:

[Test]
public void MoveForwardTest()
{
    var position = new Point(0, 0);
    var direction = new Vector(1, 0);
    double distance = 5;
    //Update position moving forward distance along direction
    position = position + distance * direction; 
    Assert.AreEqual(5.0, position.X, 1e-3);
    Assert.AreEqual(0, position.Y, 1e-3);
}
[Test]
public void RotateThenMoveTest()
{
    var position = new Point(0, 0);
    var direction = new Vector(1, 0);
    double distance = 5;
    //Create the rotation matrix
    var rotateTransform = new RotateTransform(90); 
    //Apply the rotation to the direction
    direction = Vector.Multiply(direction, rotateTransform.Value); 
    //Update position moving forward distance along direction
    position = position + distance * direction; 
    Assert.AreEqual(0, position.X, 1e-3);
    Assert.AreEqual(5.0, position.Y, 1e-3);
}
[Test]
public void CheckIfOtherCarIsInfrontTest()
{
    var position = new Point(0, 0);
    var direction = new Vector(1, 0);
    var otherCarPosition = new Point(1, 0);
    //Create a vector from current car to other car
    Vector vectorTo = Point.Subtract(otherCarPosition, position); 
    //If the dotproduct is > 0 the other car is in front
    Assert.IsTrue(Vector.Multiply(direction, vectorTo) > 0); 
}
[Test]
public void AngleToNortTest()
{
    var direction = new Vector(1, 0);
    var northDirection = new Vector(0, 1);
    Assert.AreEqual(90, Vector.AngleBetween(direction, northDirection), 1e-3);
}