Jump to content
• Advertisement

Public Group

2D Vector Representation

This topic is 4415 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm trying to create my own 2D engine using SDL even though I'm just a beginner, mainly because I learn faster this way rather than re-using already created code. I want to know what is the best form to represent a vector quantity, such as Velocity or Acceleration of an object. Here are the various options I thought of: 1) Vector( r, theta ) - Polar representation of magnitude and angle made with the horizontal X-axis. This method makes it easy to conceptualize how the vector will be, but makes the code slightly larger because you have to resolve the vectors and use the next method for addition of two vectors anyway. 2) Vector( x, y ) - Cartesian representation. This makes it easy to add/subtract multiple vectors but little harder to visualize how a vector will be in reality given values for x and y. Now since the pixel co-ordinate system has the Y-axis positive downwards, I don't know which one is better to use: 2-a) In Vector( x, y ), where y is the magnitude vertically upwards. When applying this to a moving object:
Vector Displacement = Velocity * deltaTime;
Obj->X += Displacement.X; //Add X-value of displacement vector
Obj->Y -= Displacement.Y; //Sub Y-value of displacement vector 
2-b) In Vector( x, y ), where y is the magnitude vertically downwards. When applying this to a moving object:
Vector Displacement = Velocity * deltaTime;
Obj->X += Displacement.X; //Add X-value of displacement vector
Obj->Y += Displacement.Y; //Add Y-value of displacement vector 
Which method is usually used, (1), (2a) or (2b)?

Share this post

Share on other sites
Advertisement
I'd definately go for 2, though whether A or B is up to you. However, you should make a constructor for the vector that accepts theta and r and converts them to an internal x and y, since that would be handy in some cases.

Share this post

Share on other sites
Ok I'm having a bit of problem with vector addition here:

SAGE_Vector.h

#ifndef SAGE_VECTOR_H#define SAGE_VECTOR_H#include "SAGE.h"namespace SAGE {        class Vector {                       public:                /** Horizontal Component of the vector **/        float X;                /** Vertical Component of the vector **/        float Y;          /** Constructor for defnite vector **/        Vector( float x, float y );                /** Constructor for null vector **/        Vector();                /** Destructor **/        ~Vector();                        /** Get the magnitude of the vector **/        float GetMagnitude();                /** Get the angle made my the vector with the X-axis **/        float GetAngle( bool radians = false );                /** Set the vector in polar form **/        void SetPolar( float r, float theta, bool radians = false );                /** Reverses direction of the vector **/        void Reverse();                /** Vector-Scalar Operator overloading **/        Vector operator* ( float scalar );        Vector operator/ ( float scalar );                /** Vector-Vector Operator overloading **/        Vector operator+  ( Vector v2 );        void   operator+= ( Vector v2 );        Vector operator-  ( Vector v2 );        void   operator-= ( Vector v2 );            };      };#endif

SAGE_Vector.cpp

#include "SAGE.h"#ifndef PI#define PI 3.141592654#endifnamespace SAGE {        Vector::Vector(float x, float y){        X = x;        Y = y;    }        Vector::Vector(){        X = 0.0;        Y = 0.0;    }        Vector::~Vector(){            }        void Vector::Reverse(){        X = -1 * X;        Y = -1 * Y;    }        float Vector::GetMagnitude(){        float msq = X*X + Y*Y;        float magnitude;        if( msq <= 0.0001 ){            //Null vector            magnitude = 0;        } else {            magnitude = std::sqrt( msq );        }        return magnitude;    }        float Vector::GetAngle(bool radians){        float theta;        if( fabs(X) < 0.0001 && fabs(Y) < 0.0001 ){            //Null vector            theta = 0;        } else {            theta = atan2( Y, X );            if( radians == false ){                theta = theta * 180 / PI;            }        }        return theta;    }        void Vector::SetPolar(float r, float theta, bool radians){        if( radians == false ){            theta = theta * PI / 180;        }        X = r * cos(theta);        Y = r * sin(theta);    }        Vector Vector::operator* ( float scalar ){        return Vector( X*scalar, Y*scalar );    }        Vector Vector::operator/ ( float scalar ){        return Vector( X/scalar , Y/scalar );    }            Vector Vector::operator+ ( Vector v2 ){        return Vector( X + v2.X, Y + v2.Y );    }        void Vector::operator+= ( Vector v2 ){        *this = (*this + v2);    }        Vector Vector::operator- ( Vector v2 ){        return Vector( X - v2.X, Y - v2.Y );        }        void Vector::operator-= ( Vector v2 ){        *this = (*this - v2);    }        };

Whenever I add two vectors with postive X and Y values it works fine, but when I try to add Vector( -10, 0 ) + Vector( 0, -10 ) the program crashes. At first I thought this could be a problem in the GetAngle() or GetMagnitude() function, but I'm certain its a problem with the + operator now. I don't currently have a working debugger on me so any suggestions before I can download one?

Share this post

Share on other sites
This can and probably should be all done in the header file.

#ifndef SAGE_VECTOR_H#define SAGE_VECTOR_H#include "SAGE.h"namespace SAGE {        class Vector {               // tip 1: use the single line comments for single lines            public:                // it is standard to use lowercase variables in vector classes,        // and it's always good to follow de-facto standards        float x, x;        // we use the initialiser list for our variables, and default        // arguments - they can be the same name, it's an allowed part        // of the C++ spec, and will work as expected        Vector( float x = 0, float y = 0) : x(x), y(y)        {        }                // A destructor is not required, because they are primitives                // I would make all these functions friend functions, so you        // use them like this: float x = Magnitude(my_vector);, rather        // than float x = my_vector.Magnitude();        //        // There are several reasons for this, but it's mostly a question        // of style.        // Magnitude        friend float Magnitude(const Vector& v)        {            return sqrt(v.x * v.x + v.y * v.y);        }                // we'll leave the others as an excercise for the reader                // these actually HAVE to be friend functions, because you can't        // do float * vector, you can only do vector * float (as the operators        // take the parameters as the RHS)        friend Vector operator * ( const Vector& v, float s)        {            return Vector(v.x * s, v.y * s);        }        friend Vector operator * ( float s, const Vector& v)        {            return Vector(v.x * s, v.y * s);        }        // same for the other operators                // okay: you should be using references, and returning references,        // and consting everything        Vector operator + ( const Vector& v )        {            return Vector(x + v.x, y + v.y);        }        Vector& operator += ( const Vector& v )        {            x += v.x; y += v.y;            return *this;        }            };      };

Okay, hopefully that clears some things up. I wasn't going to write the whole thing out again, but hopefully you get the gist.

Edit: Changed Magnitude() to actually work, instead of assuming.

[Edited by - _goat on September 16, 2006 12:09:40 PM]

Share this post

Share on other sites
Thanks a lot _goat, but I would also like to know why some of the things you mentioned are to be implemented. I usually like to understand the theory and reasoning behind every technique implemented, so please can you answer these questions:

1.) Why should Magnitude( V ) be used instead of V.Magnitude() ? It gives the same result and it would contain the function to be a method of the Vector class rather than being a global function who's name might clash with another function.

2.) Funtions that are declared with the friend keyword inline inside the class... will they be inside the SAGE namespace?

3.) Does the use of const enhance performance / save memory resources or something? Or is it just to prevent the change of a variable passed by referance?

4.) Why is there a return value to the += operator? Doesn't that make this legal:
v3 = ( v1 += v2 );
Or is this the reason the return type is set to Vector&, thereby returning v1 itself by referance? I think this is the case but not sure.

5.) In your Magnitude() function, this is being used:
sqrt(v.x * v.x + v.y * v.y)
Shouldn't we check that at least one of x and y is non-zero? Because in my (limited) experience, floating point numbers with a value of zero often give -0.0, which will then cause the sqrt() function to cause problems?

Thanks a lot for your help [smile]

Share this post

Share on other sites
Hi Verminox.
You've asked some good questions there. With such an inquisitive nature, you'll go far [wink].

1. There is no real reason, but it makes the code slightly more readable and can help avoid associativity errors when dealing with many nested brackets. Though, like _goat said, it's mostly a matter of style.

2. Yes, no matter who befriends the function, it will belong to the namespace it is defined in. I pulled this concise snippet from the web somewhere:
"Every name first declared in a namespace is a member of that namespace. If a friend declaration in a non-local class first declares a class or function, the friend class or function is a member of the innermost enclosing namespace."

3. Depending on the type and size of the variable in question, specifying 'const' can give performance gains or losses, but in most cases the difference is negligible. Performance purposes aside, 'const' should be used about as liberally as possible. The main reason being, of course, that it enforces good practice and helps avoid bugs. If you are really concerned about the speed difference, consider the effects of the compiler using an inline constant (as it usually will with constant primitives): If the variable is small and simple, inline compiling of consts will tend to free up registers and avoid unnecessary duplications and dereferences.

4. You're right, and that code snippet is perfectly valid, if a touch confusing.

5. A very keen observation [smile]. Taking the sqrt() of -0 will cause trouble. However, testing for equality against zero isn't a great idea as floats don't tend to equate too well. I'd guess that the best way to tackle this would be to fit a call to fabs() in before the sqrt().

Regards
Admiral

Share this post

Share on other sites
Cool... Thanks [wink]

Edit: Still having the same problem.

A vector with both x and y negative does not work :(

Vector v;v = Vector(0,0);    //worksv = Vector(10,10);  //worksv = Vector(-10,0);  //worksv = Vector(0,-10);  //worksv = Vector(-10,-10); //crashes

Edit 2: It's not a problem with the vector class, it was a problem when I was using sprintf() to get the x, y, etc. in a char buffer and then display it on the screen... I think it's called buffer overflow... when both X and Y had a negative sign to show it requird one more character than the size of the buffer.

I feel so stupid now :(

Thanks for the help guys!

[Edited by - Verminox on September 17, 2006 5:48:03 AM]

Share this post

Share on other sites
Quote:
 Original post by VerminoxEdit 2: It's not a problem with the vector class, it was a problem when I was using sprintf() to get the x, y, etc. in a char buffer and then display it on the screen... I think it's called buffer overflow... when both X and Y had a negative sign to show it requird one more character than the size of the buffer.
Ah, the perils of C :-) Fortunately, you're using C++ so you have a bevy of superior tools at your disposal for text/string output and manipulation. I'd start by looking into streaming (e.g. std::cout).

Share this post

Share on other sites
Yes but I'm not making a console app. I needed the string to be stored in a buffer to be used later with SDL_ttf to display on the screen, and specifically the std::sprintf() to format the floating numbers to the precision required and return them in string form... unfortnuately I don't know a way to make use of std::sprintf() for std::string... so I had to use a char buffer :\

Share this post

Share on other sites
std::stringstream can do the conversion and put it into a std::string

Share this post

Share on other sites

• Advertisement
• Advertisement

• Popular Contributors

1. 1
Rutin
29
2. 2
3. 3
4. 4
5. 5
• Advertisement

• 13
• 13
• 11
• 10
• 13
• Forum Statistics

• Total Topics
632959
• Total Posts
3009464
• Who's Online (See full list)

There are no registered users currently online

×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!