Sunday, January 24, 2010

My Little Litterbox and Advanced C++ Macro Tutorial

Right...
I decided to let the "El Poho" name belong to my past, since I already have a name for my one manned so called studio which is "Catbox Beta" I actually came up with a more suiting name for the engine:
Litterbox
The editor will be probably named after another cat related thing (catnip? nah... it sounds more like scripting language to me).
Litterbox inherited a lot from El Poho but it allows me to go a step farther. With every iteration of my engine I learn new tricks, I find new traps I must avoid and learn to plan more and more ahead. The results of 20 or so iterations of my engine, since the day it could barely run a pong game are quite notable. Everything is so beautifully modular I can add and remove components without much hassle. The two months I played with the Valve's Source engine didn't go to waste either! I learned the power and infinite usefulness of macros, this knowledge makes me cringe every time I hear those naysayers say that Macros are bad, and that they only replace consts and inline functions! WRONG! Macros are a nifty little way of putting text in places making creation of new classes a cinch! Get ready for some learning because here comes a class about advanced use of C Macros!

Let me give you an example:
I have a baseClass from whom every other class inherits. Of course in a typical game you would like to know the class of the instance you(for example) collided with! how can you do it? easy! add a function that returns the name of the class as a string!
so far our base class declaration would look somehow like this:


//BaseClass.h
class BaseClass
{
static string getClassName()
{
return string("BaseClass");
}
virtual string getEntityClassName()
{
return string("BaseClass");
}
};

Easy, right?
Let's make an entity that inherits from it
//Animal.h
class Animal
{
static string getClassName()
{
return string("Animal");
}
virtual string getEntityClassName()
{
return string("Animal");
}
};

We rewrote four lines of code, that's not so bad! We can just copy and paste them, and then just change the name in those two places!

now, let's consider another useful feature. we want to know if an instance of a class inherits from some class, for example we have an instance of Bird which inherits from Animal which inherits from BaseClass.
BaseClass<--Animal<--Bird if for example we want the ability to shoot an Animal we would need to know if the entity we collided with inherits from Animal. But if all we get is Bird as the classname we can't know anything about it. we'd have to write a separate hurt(int amount) code for every entity that inherits from animal! To make an inheritance check possible we'd probably do something like this:
//BaseClass.h
class BaseClass
{
static string getClassName()
{
return string("BaseClass");
}
virtual string getEntityClassName()
{
return string("BaseClass");
}
static bool classInheritsFrom(string className)
{
return className==getClassName();
}
virtual bool inherits from(string className)
{
return BaseClass::classInheritsFrom(className);
}
};

for Animal:
//Animal.h
class Animal: public BaseClass
{
static string getClassName()
{
return string("Animal");
}
virtual string getEntityClassName()
{
return string("Animal");
}

static bool classInheritsFrom(string className)
{
if (className==getClassName())
return true;
else
return BaseClass::classInheritsFrom(className);
}
virtual bool inherits from(string className)
{
return Animal::classInheritsFrom(className);
}
};

//Bird.h
class Bird: public Animal
{
static string getClassName()
{
return string("Bird");
}
virtual string getEntityClassName()
{
return string("Bird");
}

static bool classInheritsFrom(string className)
{

if (className==getClassName())
return true;
else
return Animal::classInheritsFrom(className);
}
virtual bool inherits from(string className)
{
return Bird::classInheritsFrom(className);
}
};

okay... that's a lot more rewriting and name changing this time! The programmer also has to know how to implement every single of those functions!

now, what if we could automatize all that? what if we could just say: "this class inherits from that class, now do stuff to make it all work!".
with macros such thing is not only easy, but saves a lot of time and doesn't require the programmer to understand the implementations of those functions!

//BaseClass.h
class BaseClass
{
static string getClassName()
{
return string("BaseClass");
}
virtual string getEntityClassName()
{
return string("BaseClass");
}
};

//This is where the magic happens!
#define DEFINE_CLASS(class)\
public:\
static string getClassName(){return string(#class);}\
virtual string getEntityClassName(){return string(#class);}


Now all we need to do in the animal class is this:
//Animal.h
class Animal: public BaseClass
{
DEFINE_CLASS(Animal)
};

So yeah, three lines of code less to write, no biggie...
... but in the second example things will really look diferent:
//BaseClass.h
class BaseClass
{
static string getClassName()
{
return string("BaseClass");
}
virtual string getEntityClassName()
{
return string("BaseClass");
}
static bool classInheritsFrom(string className)
{
return className==getClassName();
}
virtual bool inherits from(string className)
{
return BaseClass::classInheritsFrom(className);
}
//nothing diferent so far.
};

//This is a little bit more complicated but twice as useful!
#define DEFINE_CLASS(class,parent)\
public:\
static string getClassName(){return string(#class);}\
virtual string getEntityClassName(){return string(#class);}\
static bool classInheritsFrom(string className)\
{\
return className==getClassName();\
}\
virtual bool inherits from(string className)\
{\
return parent::classInheritsFrom(className);\
}

and finally to appreciate the result let's create our derivative classes:
//Animal.h
class Animal:public BaseClass
{
DEFINE_CLASS(Animal,BaseClass)
};
//Bird.h
class Bird:public Animal
{
DEFINE_CLASS(Bird,Animal)
};

WOW! Did you see how many lines of code we just spared ourselves?? Okay, maybe in this case not that many, but imagine if we had to write about fifty derivative classes, all with the same inbuilt functionality! And the best thing is that the programmer who'll write other classes won't have to worry at all about how to implement those functions!

This was just a tiny example. I use macros in a lot more advanced coding like defining an entity as a colidable in my engine, defining which fields save in an entity and also adding neat support for command line calling of entity functions and variables. Using macros for these things spares me literally dozens of lines of code in every entity I want to make and saves me from having to worry about the implementation of those functions once I write them to a Macro.

So, I'm hoping you find this post quite useful. In case you're interested in more posts like this feel free to say so in comments.

Later!
~Spliter

ps: yes, I do realize I started writing about my new engine and halfway through it changed from a ramble about macros to a lengthy tutorial. This post took me about (checks the clock) holy crap, an entire hour!

1 comment:

  1. For such a case, I just use dynamic_cast (assuming I have RTTI). I can see the usefulness for similar things, of course :)

    ReplyDelete