Tips on developing a Math Library for your Game Engine
If you are planning to develop your own Game Engine, then the first thing you need to do is to develop a Math Library. (I like to call it a Math Engine).
You have two options: You can either use one of many math libraries out there or you can develop your own.
I strongly advice you to develop your own Math Engine instead. Developing a game engine requires a good grasp on Linear Algebra concepts. So, developing your own math engine is a good investment that will pay off down the road.
So, assuming that you opted for developing your own math engine, I would like to share some tips with you.
Tip 1: Overload C++ Arithmetic Operators
You will be performing several arithmetic operations with vectors and matrices. Thus, you will be tempted to create an "Add()" method which adds two vectors together. This is OK, but not optimal. It is better to overload the "+" operator in C++ so that it can add vectors.
For example, the following shows the "+" operator being overloaded to add vector components:
Vector3n operator+(const Vector3n& v){
//assume a vector is composed of x, y and z components
return Vector3n(x+v.x,y+v.y,z+v.z);
}
In practice, you simply do the following whenever you need two add two vectors:
Vector3n a(1,3,1); //init vector a
Vectorn3n b(4,2,1); //init vector b
Vector3n c=a+b; //add vectors a and b
Vector3n d=a+b+c; //adding vectors
This is definitely better than doing this:
Vector3n a(1,3,1); //init vector a
Vectorn3n b(4,2,1); //init vector b
Vector3n c=a.add(b); //add vector a and b
Vector3n d=(a.add(b)).add(c); //adding vectors
Tip 2:Don't use Setters or Getters
In every OOP book, you will find a section dedicated to data encapsulation. Data encapsulation states that data-members should only be accessible by set() and get() methods and that they should be private. This is a rule to always keep in mind but from experience, you should break this rule when developing a Math Engine.
Why?
Imagine that you want to do some crazy computations with the components of a vector. Using getter methods, it would look like this:
v.getX()+v.getZ()*a.getY()/a.getZ()+v.getY()
However, if I don't use getters, the code looks cleaner:
v.x+v.z*a.y/a.z+v.y
Rules are meant to be broken, but only if you know what you are doing. I strongly suggest to not use setters/getter in your math engine. But only if you feel comfortable with OOP design.
Tip 3: Initialize all data members
In C++, the data members of a class are sometimes initialize to zero, other times they are not. Make sure that all constructors initialize everything in the object. Read This.
The keyword here is Initialize NOT Assign.
For example, the code below shows the constructor assigning values to the vector components:
class Vector3n{
public:
float x; //x-componet of vector
float y; //y-componet of vector
float z; //z-componet of vector
Vector3n(float uX, float uY, float uZ){
x=uX; //These are assignments, NOT initialization
y=uY;
z=uZ;
}
};
The constructor above is not initializing its members, it is assigning data to them. It turns out that in C++, data members of an object are initialized before the body of a constructor is entered. So in the class above, the initialization of the members took place before the constructor was called.
So to truly initialize the members, write the constructor with a member initialization list. For example:
class Vector3n{
public:
float x; //x-componet of vector
float y; //y-componet of vector
float z; //z-componet of vector
//Constructor
Vector3n(float uX, float uY, float uZ):x(uX),y(uY),z(uZ){}
};
Hope these tips help.
PS. Sign up to my newsletter and get Game Engine development tips.