Search code examples
c++normalsnormalizemagnitude

C++ Magnitude (Normalise) doesn't seem to be correct


I'm doing a little 2D tank turret game where you rotate a tank in the middle of a screen, click your left button and then a little projectile moves to that location.

I'm currently at the point where I have a current location and a desired location, what I need to do now is to get the magnitude of those two points, which should either return 1 or 0.

This is my C++ VectorClass magnitude function:

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

This is the code where I normalise my desired and current location:

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);

The current position is tied to the middle of my laserTexture, which is a fixed rotating point in the middle of the screen.

My desired location is a mouse click which returns the position in X and Y (This works).

Maths isn't my strong point, so when it comes to programming this sort of stuff I struggle more then other people do, so it takes me a lot longer / i'll just come up with some not very elegant solution.

My end goal is to get the normalised location, and then when the left mouse button is clicked the tank turret will fire, and the projectile will get to move to the desired location.

So to clarify:

  • Is my magnitude function correct?
  • Am I normalising my desired and current positions correctly?

Thanks


Solution

  • ad 1.) "Is my magnitude function correct?"

    No, you have little error in your maginutude() method. Yours:

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

    is

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

    is

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

    but you probably wanted to write this:

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

    EDIT:

    I originally wrote that sqrt(x*vec2.x+y*vec2.y) is correct, but it's not, correctly it's this:

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

    and that's because OP wanted to calculate magnitude of only vec2, there is no need to use this.x and this.y. For this reason I would further suggest to change your method to static:

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

    or use only instance values:

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

    in this, second case, you would need to use the magnitude() method like this:

    (desiredPos - currentPos).magnitude();
    

    Further notes:

    • Result of this method is magnitude and not normalization (of anything), but can be used to normalize given vector.
    • This result is equal to distance between desiredPos and currentPos.
    • If you divide (desiredPos - currentPos) by the magnitude value, you'll get normalized vector which is direction from currentPos to desiredPos.
    • It's obvious, but if desiredPos and currentPos are equal, magnitude is zero and you cannot normalize the vector.
    • For reasons above, I would rename the normalisedLocation variable. It distance, as stated above.

    Ad 2.) "Am I normalising my desired and current positions correctly?"

    I'm not sure how to understand this question, because you don't normalize anything in the example code. Anyway, look at this:

    // 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.
    }
    

    However there is still a catch. It's following lines:

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

    With this, you calculate center of laser texture, however this position is correct only if laser is rendered at [0, 0] position. Otherwise you need to update it like this:

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

    where laserPos is position where your laser is currently located.