Lua and C++ binding libraries

Started by
7 comments, last by Amar0k 18 years, 8 months ago
I've just finished giving myself a crash course in Lua and I can't wait to make it do something. I've heard of a lot of different libraries for mapping C++ and Lua together (luabind, tolua, etc.). Should I use one of these and if so, which one? Some advice on the strengths and weaknesses from somebody who knows what they're talking about would be good. Another thing is what functionality should I expose to the scripts from my engine, how should I design the engine to factor in scriptability and what parts of the game logic should be scripted? As before, advice from people who've actually done game scripting before would be much appreciated.
Advertisement
What functions you expost to your scripts depends a lot on what kind of game you are making and what you want to use your scripts for. The answer is going to be fairly different between a turn based board game clone where you use scripts to implement the different things that happen when you land on different squares and a first person shooter where you use scripts to handle AI.
I'm currently looking at scripting for an RTS-type project. The project is in C++, and I'm building my engine as I go along (this is mostly a learning project).
I used LuaBind briefly, and after the initial headache of getting it to compile (it relies on boost::mpl, which can cause headaches in and of itself) it was pretty cool. It allowed some things that my main tool, tolua, does not, but in the end they were things that I did not really find all that necessary, and I've returned to using tolua.

Tolua is really simple to use. You do a little bit of processing work on the headers for whatever classes and external functions/globals/etc... you want to make visible to the script, and it generates a .cpp file with two calling points (an open and a close function) which are called with a Lua state. Once the open function is called, those classes and functions can be accessed through script.

In my work, I use a pretty thorough interfacing between script and engine, since all of my levels are randomly generated and populated. I expose to the script state all of the various classes I need to manipulate (static objects, the map builder object, creatures, etc... although I may not expose all methods of these classes to script; just the ones necessary for level creation) and do all my level generation work in script. You can check out some of my random level generation tutorials (such as this one, which is the introductory article for my Accidental Engine project, and which explains some of the level generation interface and exposed functionality) for a little better idea of some of the things I expose to script. In a more mature project (Accidental was never meant to be a full game) even more things would be exposed, involving AI and decision making, GUI construction, etc...

The biggest sticking point I have found with tolua is the awkwardness involved in exposing objects of which there is only 1 instance. Back when I still used singletons, it was easy as I simply exposed the class's Instance() function which would obtain a pointer to the object. I've since eliminated singletons, so now I typically use an intermediate class (a monostate or even a singleton as the sole exception to the rule; I call this class a Relay) to pass these 1-instance objects (object creation factories, the map builder, etc...) to the script interface. I have not yet come up with an elegant solution to the problem, outside of doing manual Lua stack and state hacking separate from tolua binding, and I am reluctant to go this route. So for now I just stick with the relay class. It usually is a monostate, with all static methods and members and with a list of various Get() style functions like GetMapBuilder() which returns a pointer to the map builder object used for constructing levels. Since the map builder class is also exposed to the script interface, I can then use this returned pointer from script to call the various generation functions.
Thanks a heap. Rating++
LuaBind is really nice, the problem is that if something goes wrong you might need to hire somebody to debug the code :-P

Interfacing with Lua is simple enough that unless you need some really special features, I would suggest to create the interfacing yourself.
Hi,

I'm also in the process of switching to toLua++ (ditched luabind, too much hassle). However I can't figure out how to export a variable to Lua. i.e. with luabind one would register one's class and then simply call
 luabind::get_globals(l)[var_name] = var_ptr 
and luabind would (presumably) do all the dirty work of figuring out what type the var was and passing it to Lua.
toLua doesn't seem to have a mechanism for this. I'm a bit lost on how to achieve that.

Thanks in advance,
Daniel
.Amar0k."In the beginning the Universe was created. This has made a lot of people very angry and been widely regarded as a bad move." -- Douglas Adams
Of course, super-hack style, I can always add a GetMe() { return this; } method to all my exported classes and simply
 lua_dostring(l, ( var_name + " = " + this->GetMe()).c_str() ); 
though I haven't tried that yet... I will wait to see if anyone answers before doing that...

edit: Duh... scrap that! [ignore] (now i'm really ashamed... still good for a laugh though)
.Amar0k."In the beginning the Universe was created. This has made a lot of people very angry and been widely regarded as a bad move." -- Douglas Adams
As far as hacking goes I was able to come up with a temporary solution (dont mind that last post, late hours make my logic kinda alien).

What I need is to pass to Lua a bunch of objects stored in a stl map as pointers to their base class. But the problem is that I needed those globals to actually have the type of the derived object. That would be easy if I knew how to pass the object directely to Lua.
 luabind::get_globals(l)[this->Name()] = this 
What the hack does is to create a global in lua by calling lua_dostring with a string of the form
 obj->name = Manager:GetElement("obj->name") 
and then casting to the derived class
 tolua.cast(obj->name, obj->Type()) 
where obj->Type() returns a string representing the correct toLua type of the object.

I'm not too familiar (yet) with the inner workings of Lua and the lua stack. I hope someone familiar with Lua and toLua can nudge me in the right direction to find a better solution for this.

Cheers,
Daniel
.Amar0k."In the beginning the Universe was created. This has made a lot of people very angry and been widely regarded as a bad move." -- Douglas Adams

This topic is closed to new replies.

Advertisement