C ++ Magnitude(Normalize)似乎不正确

时间:2014-05-27 11:53:14

标签: c++ normals normalize magnitude

我正在做一个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中的位置(这有效)。

数学不是我的强项,所以当谈到编程这类东西时,我比其他人更挣扎,所以它花了我更长时间/我会想出一些不太优雅的解决方案。

我的最终目标是获得标准化位置,然后当点击鼠标左键时,坦克炮塔将会发射,并且射弹将移动到所需的位置。

所以澄清一下:

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

由于

4 个答案:

答案 0 :(得分:5)

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变量。它的距离如上所述。

广告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是您的激光当前所在的位置。

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

矢量的大小,即其长度,将是

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;

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

答案 3 :(得分:0)

为什么你需要幅度?你需要一个角度(度数或弧度)的方向。因为你已经拥有坦克的基本位置,以及你点击鼠标所需的位置,你需要计算它们与点的角度。你可以用一点点毕达哥拉斯和三角测量法找出角度,将你的坦克旋转到那个角度,然后在同一个航向上发射你的射弹。