Friday, September 9, 2011

Using the benefits of lambda functions with a component based game object model

Hi everybody!

Today I'd like to introduce a feature of the new C++11x standard, which is implemented in the Visual C++ compiler of the 2010 edition of visual studio and newer versions of gcc.

The new feature I'd like to talk about is the Lambda Function.

A Lambda Function is an anonymous function...
What exactly that means is demonstrated in the code below.

I'm going to refer to my last blog post (Component based game objects) and take components as an example.

 class IComponent
{
public:
virtual void update(float gameTime) = 0;
virtual bool handleMessage(Event const & componentEvent) = 0;
};
This is the (simplified) interface I'm using for components.

Now think about what you would do if you have, for example, a game object which needs to respond to mouse movement events.

You really need this behaviour only for this particular object and nothing else.

So far one had to write a new IComponent implementation for this.
Think about the mass of this kind of components you'll have at the end of your project...

Fortunately the Lambda Functions will help us with the mass of implementations for this "one purpose components".

Consider the following IComponent implemention:

 typedef std::function<void(float)> UpdateFunction;
typedef std::function<bool(const Event)> HandleEventFunction;
class VersatileComponent : public IComponent
{
public:
VersatileComponent(UpdateFunction updateFunc,HandleEventFunction handleFunc){
this->m_updateFunction = updateFunc;
this->m_handleFunction = handleFunc;
}
void update(float GameTime){
m_updateFunction(GameTime);
}
bool handleEvent(const Event &gameevent){
return m_handleFunction(gameevent);
}
private:
UpdateFunction m_updateFunction;
HandleEventFunction m_handleFunction;
};

What this component does is taking 2 functions as parameters and performing them.
(for those of you who are not familiar with std::function (or std::tr1::function) check out Effective C++ (Scott Meyers has some great items in there which covers std::function) or this link.)

What you can do with the above implementation is something like this:

 bool handleMouseMovement(const Event &gameEvent){
if(gameEvent.getType() == MouseMovement){
//DoStuff
}
}
void update(float deltaTime){
//DoStuff
}
int main()
{
VersatileComponent *vComponent = new VersatileComponent(update,handleMouseMovement);
//DoStuff
}

Here we just define 2 functions which takes the same parameters and return the same types as the update and handle function of the VersatileComponent class... We just pass them as parameters so they get called in the VersatileComponent update() and handleMouseMovement() function.

(Look here if you need a refresh in function pointers)

So...That's nothing new so far, but now I'm going to use Lamda Functions (or anonymous functions, if you prefer).

I'm just going to throw this code at you, before I'll do any explanation:
 int main()
{
VersatileComponent *vComponent = new VersatileComponent([](float gameTime){
//DoUpdateStuff
},[](const Event &gameEvent)->bool{
if(gameEvent.getType() == MouseMovement){
//DoStuff
}
});
//DoStuff
}
I know this does look weird at first, but I'm just doing the same as in the previous code example...I'm passing two functions as parameters...two Lambda Functions.

As you might see, Lambda Functions are getting defined at the point where they are needed.
They don't get named (well they get internally,but you don't know the name of them), so you can't call them in other places of your code.

They also have some kind of unique initialization syntax, which you can look up here (the link also features more informations about Lambda Functions).

The benefit of this approach is, that you don't have to declare functions in other places of your code only because you need them once. (see the example with the function pointers)

With the new Lambda Functions the VersatileComponent truly gets maximum versatileness.

BTW: Just for your information : I don't get nothing for linking to Amazon items. ;)