We've all probably heard that Lua (and scripting languages in general) can come in handy when writing games. And if you haven't heard that, you just have. In this guided example I will walk you through the process of binding a C++ class to Lua and manipulating it from a script.
But why, if you're already going through the trouble of writing a game in a compiled language such as C++, would you introduce an interpreted layer of potential slowness? Well when it comes down to it, the performance of the program isn't as important as the performance of the programmer. Lua, when used strategically, can be a real timesaver for development with negligible effect on framerate. And with the right amount of game logic implemented in Lua, you can develop large chunks of your game without ever having to recompile! Hell you could even reload your scripts during runtime and develop without ever closing the game. This can do wonders for your flow, allowing you to work and test lots of small changes without regular interruption caused by compilation.ScopeOf course finding this sweet spot takes careful consideration. Ultimately it's up to you to figure out what will be implemented in C++ and what will be offloaded to scripts. Be aware that it might take you several iterations (read: attempts that go to shit) before you get "good" at defining that line. Fortunately it gets easier the more you practice, so even if you screw up it will still benefit you.As for me personally, I'm still in the early stages of understanding, so bear with me. The main purpose of this guide is to spark your interest rather than show you the "right" or "best" way to do things.CodeThe full source code for this example can be downloaded here. For brevity I'll just refer to relevant snippets as we go along.SLBThere are plenty of solutions available for binding your code to Lua, but I'm going to be focusing on Simple Lua Binder, since it's quite easy to jump into. I used the SLB-2.00_amalgamation, which contains a minimal number of files that can be added directly into your project. This bundle includes lua itself, so no need to worry about getting that separately. Note that everything is included in the example zip above, so you don't need to download SLB again unless you really want to.Dialogue classFor my example, I am going to have two important classes, the first of which is Dialogue. Dialogue is a simple class that holds some information about a part of a conversation. The definition looks like this:class Dialogue {
public:
Dialogue(std::string message_text, std::string next_function);
void addChoice(Dialogue* choice);
std::string getChoice();
//Message text
std::string message;
//Name of function to call for the next message
std::string next;
protected:
std::vector<Dialogue*> choices;
};
SLB::Manager m;
SLB::Class< Dialogue >("Dialogue",m)
.constructor<std::string,std::string>()
.set("addChoice", &Dialogue::addChoice);
local d = SLB.Dialogue('Whatcha doing in my waters?','')
d:addChoice(SLB.Dialogue('Nothing..', ''))
d:addChoice(SLB.Dialogue('Not fishing...', ''))
class DialogueScript : public SLB::Script {
public:
DialogueScript(SLB::Manager* m);
Dialogue* getDialogue(std::string s);
};
DialogueScript::DialogueScript(SLB::Manager* m) : Script(m) {
doFile("default.lua");
}
Dialogue* DialogueScript::getDialogue(std::string lua_function_name) {
lua_State *L = getState();
SLB::LuaCall<Dialogue*(void)> call(L,lua_function_name.c_str());
Dialogue* d=NULL;
d = call();
return d;
}
function test()
local d = SLB.Dialogue('Are you playing those love games with me?','')
d:addChoice(SLB.Dialogue('Wow I didn\'t realize I liked watercolors so much', ''))
d:addChoice(SLB.Dialogue('Baileys... so creamy', ''))
return d
end
DialogueScript s(&m);
Dialogue* d = s.getDialogue("test");
DialogueScript s(&m);
Dialogue* d = s.getDialogue("main");
while(d!=NULL) {
std::string next = d->getChoice();
if(next.length()>0)
d = s.getDialogue(next);
else d = NULL;
}
function yourThoughtsPlease()
local d = SLB.Dialogue('What do you think of me?','')
d:addChoice(SLB.Dialogue('You\'re alright I guess...', 'alright'))
d:addChoice(SLB.Dialogue('I don\'t know, sir...', 'idk'))
return d
end
function alright()
return SLB.Dialogue('Do you love me?','')
end
function idk()
return SLB.Dialogue('Make an assessment.','')
end
What do you get when you multiply six times nine?
1. Fifteen
2. Fifty four
3. Fourty two
4. I suck at math...
> 2
What are you, in base 10?
Okay I'll ask you again... What do you get when you multiply six times nine?
1. Fifteen
2. Fourty two
3. I suck at math...
> 2
You are enlightened. Are you a wizard?
1. I think I am!
2. No way!
> 2
Don't be modest now, only a wizard would say he's not a wizard. I know from experience.
Would you like to turn into a whale?
1. Yeah buddy!
2. WHAT?! No!!
> 1
Poof! You turn yourself into a whale! Wowee, that was crazy!
You can even export the full load of the lua game and save it for later and then load it back up later assuming that no external resources were required. [That can be quickly bypassed with some extra effort.]
Cool. I recently started to make my project lanarts use this (SLB) a few days ago. One nifty thing I found was that if you hack onto SLB::Private namespace and provide overloads for Type<> you can get nifty results such as eg wrapping a colour structure as a lua array and vice versa (eg passing {255,0,0} as a colour.)
SLB is definitely a good middle-ground sensible option for lua bindings (without using Boost).