【问题标题】:C++ Magnitude (Normalise) doesn't seem to be correctC++ Magnitude (Normalise) 似乎不正确
【发布时间】:2014-07-16 07:50:23
【问题描述】:

我正在做一个小型 2D 坦克炮塔游戏,您可以在屏幕中间旋转坦克,单击左键,然后一个小弹丸移动到该位置。

我目前处于我拥有当前位置和所需位置的点,我现在需要做的是获取这两个点的大小,它应该返回 1 或 0。

这是我的 C++ VectorClass 幅度函数:

float vector2D::magnitude(vector2D vec2)//<! Vector magnitude
{
    float result;
    result = (sqrt(x*vec2.x)+(y*vec2.y));
    return result;
}

这是我将所需位置和当前位置标准化的代码:

currentPos.x = laserTexture.getSize().x/2.0f;
currentPos.y = laserTexture.getSize().y/2.0f;
desiredPos.x = sf::Mouse::getPosition().x;
desiredPos.y = sf::Mouse::getPosition().y;
normalisedLocation = magnitude(desiredPos - currentPos);

当前位置绑定在我的laserTexture的中间,这是屏幕中间的一个固定旋转点。

我想要的位置是鼠标单击,它返回 X 和 Y 中的位置(这有效)。

数学不是我的强项,所以在编写这类东西时,我比其他人更努力,所以我需要更长的时间/我只会想出一些不太优雅的解决方案。

我的最终目标是获得归一化的位置,然后当点击鼠标左键时,坦克炮塔会开火,炮弹会移动到所需的位置。

所以澄清一下:

  • 我的幅度函数正确吗?
  • 我是否正确规范了我想要的和当前的位置?

谢谢

【问题讨论】:

  • 幅度是什么意思?你是说规范吗?如果是,那么你的函数确实不正确。
  • 是的,很抱歉造成混乱。问题是,当我计算 normalisedLocation.xnormalisedLocation.y 时,它只会打印出 0。
  • 我不明白,在你的代码中magnitude 返回一个float,你如何访问.x.y?这没有意义。
  • 好点!将代码更改为更新代码以实际使用总和,然后我将实际函数更改为 sqrt(x*x + y*y) 其中xy 是我向量中的开始和结束位置

标签: c++ normals normalize magnitude


【解决方案1】:

ad 1.) “我的幅度函数正确吗?”

不,您的 maginutude() 方法几乎没有错误。你的:

result = (sqrt(x*vec2.x)+(y*vec2.y));

result = sqrt(x*vec2.x)+(y*vec2.y);

result = sqrt(x*vec2.x) + (y*vec2.y);

但你可能想写这个:

result = sqrt((x*vec2.x)+(y*vec2.y));

编辑:

我最初写sqrt(x*vec2.x+y*vec2.y)是正确的,但它不是,正确的是这样:

result = sqrt(vec2.x*vec2.x + vec2.y*vec2.y);

那是因为 OP 只想计算 vec2 的大小,所以不需要使用 this.xthis.y。出于这个原因,我会进一步建议将您的方法更改为静态:

static float vector2D::magnitude(vector2D vec2)//<! Vector magnitude
{
    return sqrt((vec2.x*vec2.x)+(vec2.y*vec2.y));
}

或仅使用实例值:

float vector2D::magnitude()//<! Vector magnitude
{
    return sqrt((x*x)+(y*y));
}

在第二种情况下,您需要像这样使用magnitude() 方法:

(desiredPos - currentPos).magnitude();

补充说明:

  • 此方法的结果是幅度而不是归一化(任何东西),但可用于对给定向量进行归一化。
  • 此结果等于desiredPoscurrentPos 之间的距离。
  • 如果您将(desiredPos - currentPos) 除以幅度值,您将得到归一化向量,即从currentPosdesiredPos 的方向。
  • 很明显,但如果 desiredPoscurrentPos 相等,则幅度为零,您无法对向量进行归一化。
  • 出于上述原因,我将重命名normalisedLocation 变量。它的距离,如上所述。

Ad 2.) “我是否正确地规范了我想要的和当前的位置?”

我不确定如何理解这个问题,因为您没有对示例代码中的任何内容进行规范化。不管怎样,看看这个:

// This is from your code:
currentPos.x = laserTexture.getSize().x/2.0f;
currentPos.y = laserTexture.getSize().y/2.0f;
desiredPos.x = sf::Mouse::getPosition().x;
desiredPos.y = sf::Mouse::getPosition().y;

// Store direction to desired position. Currently length of this vector is
// distance between the two points.
vector2D dirToDesiredPos = (desiredPos - currentPos);

// Calculate distance between the two points.
float dirToDesiredPosDist = magnitude(desiredPos - currentPos);

// Detect whether the distance is zero. Problem is, you cannot compare float
// with zero (computer is not accurate enough) so we compare it with a delta
// value. It should be some small number, for example 0.01f.
// (Note that in this case we don't need to compare it with negative value -
// which would be -0.01f, because distance is always positive or zero.)
if(dirToDesiredPosDist < FLOAT_DELTA)
{
    // User clicked on the tank, we cannot shoot!!!
}
else
{
    // Following two lines do actuall normalization - direction of this vector
    // is unchanged, but it's length is currently 1.
    dirToDesiredPos.x /= dirToDesiredPosDist;
    dirToDesiredPos.y /= dirToDesiredPosDist;

    // Now dirToDesiredPos can be used to calculate to move your bullet to the
    // desired location.
}

但仍有一个问题。如下几行:

currentPos.x = laserTexture.getSize().x/2.0f;
currentPos.y = laserTexture.getSize().y/2.0f;

这样,您可以计算激光纹理的中心,但是只有当激光在 [0, 0] 位置渲染时,该位置才是正确的。否则你需要像这样更新它:

currentPos.x = laserTexture.getSize().x/2.0f + laserPos.x;
currentPos.y = laserTexture.getSize().y/2.0f + laserPos.y;

laserPos 是您的激光当前所在的位置。

【讨论】:

  • 感谢您的一点澄清,但最终结果他们不做同样的事情吗?编辑:看到你的小修改,完全忽略了原来的括号,哎呀!
  • @JohnathanBrown 在您的情况下,您计算 sqrt(x1*x2) + y1*y2,在我的情况下它是 sqrt(x1*x2 + y1*y2)。
  • @JohnathanBrown 好的,我扩展了我的答案,所以如果您对我身边的示例代码的更多细节和一些 cmets 感兴趣。
【解决方案2】:

向量的范数是其坐标的平方和的平方根。你的方法应该是:

float vector2D::magnitude(vector2D vec2)
{
    return sqrt(vec2.x * vec2.x + vec2.y * vec2.y);
}

【讨论】:

    【解决方案3】:

    为什么需要幅度?您需要方向,它是一个角度(度数或弧度)。因为您已经有了坦克的基本位置,以及单击鼠标的所需位置,因此您需要计算这些点的角度。借助一点毕达哥拉斯和三角函数,您可以计算出角度,将您的坦克旋转到该角度,然后以相同的方向发射您的弹丸。

    【讨论】:

      【解决方案4】:

      你的向量的大小,即它的长度,将是

      float vector2D::magnitude() const
      {
          return sqrt(x*x + y*y);
      }
      

      (它是边 x 和 y 的直角三角形的斜边。)

      要对一个向量进行归一化,即得到一个方向相同但长度为 1 的向量,可以将其坐标除以其大小:

      vector2D vector2D::normalise() const 
      {
          float length = magnitude();
          // Do something suitable to handle the case where the length is close to 0 here...
          return vector2D(x / length, y / length);
      }
      

      你的最后一行是

      normalisedDirection = (desiredPos - currentPos).normalise();
      

      或者,更详细的

      vector2D direction = desiredPos - currentPos;
      normalisedDirection = location.normalise();
      

      (我重命名了一个变量以澄清我们正在计算一个方向,而不是一个位置。)

      或者,您可以使用免费函数:

      float magnitude(vector2D v)
      {
          return sqrt(v.x * v.x + v.y * v.y);
      }
      
      vector2D normalise(vector2D v)
      {
         float length = magnitude(v);
         v.x /= length;
         v.y /= length;
         return v;
      }
      
      // ...
      
      normalisedDirection = normalise(desiredPos - currentPos);
      

      旁注:
      您的函数中有一个错字,导致它更加不正确:

      (sqrt(x*vec2.x)+(y*vec2.y));
      

      很像

      sqrt((x*vec2.x)+(y*vec2.y));
      

      因为末尾有两个括号,但实际上是

      sqrt(x * vec2.x) + y * vec2.y;
      

      为了避免这些问题,第一:不要害怕空格键,第二:不要使用过多的括号。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-12-03
        • 2012-06-09
        • 2023-01-08
        • 2017-04-20
        • 2015-12-02
        • 2012-01-04
        • 2011-04-20
        相关资源
        最近更新 更多