• Advertisement
  • 05/21/00 12:40 AM
    Sign in to follow this  

    Implementing 2D Vectors

    General and Gameplay Programming


    In my explorations as a beginner game-programmer across the web and various books, I have not yet found a document that satisfactorily explains how to implement vectors in a game. Sure, I found numerous documents on: vector math, drawing lines, vector classes and physics. But I couldn't find a document that explains how all these things play a part in making a game. A document on vector math doesn't deal with the twisted co-ordinate system of a computer screen. A document on drawing lines doesn't explain how to represent a line as a class. A Vector class document doesn't explain operations on that class. A physics document doesn't give you any useful algorithms for your program. This document attempts to satisfy all the shortcomings of those other documents. This document will use C++ notation for examples because to me there is only ONE language.

    [size="5"]A Vector (class)

    Vectors in general can be represented in 2 ways.
    [bquote]1: by a length and an angle
    2: by a begin and endpoint[/bquote]These two methods each have their own math. Method 1 uses trigonometry to calculate angles and normals. Method 2 uses matrix math to calculate rotations and other operations. In this document we'll implement a vector represented by method 1.

    Here's the class listing:

    class C2DVector
    long x,y; //Endpoint coordinates
    int angle; //Angle of vector
    long length; //length of the vector
    void SetX( long Xin ); //Set the X element of the endpoint
    void SetY( long Yin ); //Set the Y element of the endpoint
    void SetLength( long Lin ); //Set the length in pixels
    void SetAngle( int Ain ); //Set the angle in degrees

    long GetX(); //Get the X element of the endpoint
    long GetY(); //Get the Y element of the endpoint
    long GetLength(); //Get the length
    int GetAngle(); //Get the angle

    void operator=(C2DVector aVector); //Make this vector equal with another

    C2DVector(); //constructor
    C2DVector( long Xin, long Yin ); //overloaded constructor
    ~C2DVector(); //destructor
    I'll have to explain some things about this implementation of a Vector class.

    You'll notice that I included the endpoint in my class while I said earlier that you only need an angle and length to specify a vector. I chose to include the endpoint because of efficiency. You need a cosine and sine function to calculate the endpoint. By storing the endpoint we only have to do this calculation once every time the endpoint changes instead of every time we want to use the endpoint. The length of the vector is specified in amount of pixels but that could easily be modified to anything you want.

    Another important thing to keep in mind is the co-ordinate system we use. Normal vector mathematics usually uses the Cartesian coordinate system.

    A Cartesian co-ordinate system looks like this:


    The computer designers of course chose a different approach to deal with things (as usual).

    A computer screen uses the following co-ordinate system:


    To make it easy for ourselves (so we don't need to rebuild a lot of formulas) we will use the Cartesian co-ordinate system. Later in this document I'll tell you how to convert your co-ordinates from 1 system to the other and back.

    The angle that we use in our class is the angle between the vector and the positive X-axis.


    There are some numbers you'll need for the calculations. We need cosine and sine to calculate rotations. Experienced readers will have noticed that I store the vector angle in degrees while most math libraries use radians to calculate sine and cosine. So we'll need to convert our degrees to radians for these functions. For that we need PI so let's define PI.

    #define PI 3.141592654
    Again for efficiency I am going to store both sine and cosine values for every angle in an array so we don't need to use those slow sin() and cos() routines every time. So let's declare those:

    float costable[360];
    float sintable[360];
    We'll also need a routine to fill these tables.

    This function needs to convert degrees to radians, which can be done by:
    [bquote]rad = deg / 180 * PI[/bquote]
    void InitTables()
    float temp;
    for( int i = 0; i<360; i++ )
    temp = ((float)(360-i)/180;
    //cast needed for calculation
    //I use (360 - i) to compensate for the weird screen coordinates

    temp *= PI;

    costable = (float)cos( temp );
    sintable = (float)sin( temp ); }

    [size="5"]The class definition

    Now that we're prepared let's look at the 2 most important functions of our class. SetLength( long Lin ) and SetAngle( long Ain ) these functions cause a new endpoint to be calculated and stored.

    We can do this using the following calculation:
    [bquote]x = cos(angle) * length
    y = sin(angle) * length[/bquote]
    Here's what the functions look like in our code:

    void C2DVector::SetLength( long Lin )
    length = Lin;
    x = costable[angle]*length;
    y = sintable[angle]*length;

    void C2DVector::SetAngle( int Ain )
    angle = Ain;
    x = costable[angle]*length;
    y = sintable[angle]*length;

    [size="5"]How to use this class

    Now that we have a vector class we want to put it to use.

    Well let's use a pooltable to test our vector.

    In this scenario we'll have an object Ball which will use a vector to keep track of it's velocity.

    This is quite simple we just move our ball around by specifying an angle and a length and then we keep adding the endpoint x,y to the x,y of the ball.

    A problem arises when our ball hits a cushion on the pooltable. When this happens we'll have to calculate a new velocity vector so our ball will bounce naturally. If we now the normal of the cushion we can calculate the new vector as follows:
    1. invert the velocity vector
    2. calculate delta( v, n )
    3. angle = angle +/- delta( v, n)
    Here's the code:

    void CBall::HitBoundary( C2DVector* BoundaryNormal )
    int angle; //the new angle
    int OppAngle; //the inverted old angle
    int NormDiffAngle; //difference between the inverted angle & the BoundaryNormal angle

    angle = Velocity.GetAngle();
    OppAngle = (angle + 180) % 360;
    if( BoundaryNormal->GetAngle() >= OppAngle )
    NormDiffAngle = BoundaryNormal->GetAngle() - OppAngle;
    angle = (BoundaryNormal->GetAngle() + NormDiffAngle) % 360;

    if( BoundaryNormal->GetAngle() < OppAngle )
    NormDiffAngle = OppAngle - BoundaryNormal->GetAngle();
    angle = BoundaryNormal->GetAngle() - NormDiffAngle;
    if( angle < 0 ) angle += 360;

    Velocity.SetAngle( angle );
    In the implementation of my Vector class I adjusted for the weird screen coordinate system. But if you ever need to convert Cartesian coordinates to the screen you can do this as follows:

    void ConvertCoordinates( long* X, long* Y, BOOL convert )
    int Xmiddle;
    int Ymiddle;
    Xmiddle = (int)(XRES/2); //XRES is the Screen resolution in the x direction
    Ymiddle = (int)(YRES/2); //YRES is the Screen resolution in the y direction

    if( convert)
    *Y = -*Y;
    *X = *X + Xmiddle;
    *Y = *Y + Ymiddle;
    *X = *X - Xmiddle;
    *Y = *Y - Ymiddle;
    *Y = -*Y;


    Now you know how to effectively use vectors in your games. You'll be suprised at the number of situations you can apply vectors in, especially in games. I've included links for some sample code at the top of this page.

      Report Article
    Sign in to follow this  

    User Feedback

    Create an account or sign in to leave a review

    You need to be a member in order to leave a review

    Create an account

    Sign up for a new account in our community. It's easy!

    Register a new account

    Sign in

    Already have an account? Sign in here.

    Sign In Now

    There are no reviews to display.

  • Advertisement