If you want to cut to the chase you can download the code here.
This isn’t a very well written blog post, it’s more of a dump of my thoughts as I tested out LuaBridge and didn’t get to trying out OOLua.
Once again I am starting to integrate Lua in to the next generation of my engine. It’s never a completely smooth process. Exactly where to draw the line between C++ and Lua logic is never immedietly clear.
This is the fifth major revision of my engine (that I can remember) and it’s move toward a component based system has made the dividing line more obvious.
Previously I had driven the engine completely from Lua, the main loop essentially being the first script that the engine loaded. This script drove everything. With a component based system and a new custom editor the “data driving” is done by the editor as it packs levels or scenes together.
Bridging the divide
In previous incarnations of my engine integration of Lua and C++ has be done with:
I never want to handcraft it ever again, it’s just too time consuming and brittle. SWIG, while easy to use and clever, produces glue code that is slower than needs be and very complicated. tolua++ produces better code than SWIG and has some really nice features but seems to be unmaintained and there are some bugs that need to be worked around.
LuaBridge over OOlua
OOLua has some nice tables showing it is the fastest thing in the world which enticed me BUT it requires Premake, Cpp Unit and Google Mock to build it. This really put me off. I just want to wrap my code, not install another build system and unit testing framework. LuaBridge doesn’t require any external tools or libraries.
LuaBrdge has a more pleasant syntax and the underlying template code seems easier to decipher. To expose a simple struct (taken from the OOLua docs)
1 2 3 4
In OOLua you would enter:
1 2 3 4 5 6 7
while in LuaBridge:
1 2 3 4 5
LuaBridge seems more concise, less brittle (it uses C++ templates to infer the paramter types and return types) and quite frankly who wants CAPITALS ALL THROUGH THEIR CODE?
Both seem like very well written libraries though so it’s really a matter of personal preference as opposed to some major technical flaw in OOlua.
So I decided to test LuaBridge first. If I could get what I wanted from it then I’d move forward.
Overview of Requirements.
The scripts that I want to attach to my
GameObjects are more like behaviours than massive all emcompassing AI scripts. This design is something I learned to like while playing with Unity3D a few months ago. While it adds a certain amount of managment overhead on the engine side it allows a lot of the day to day scripting of a game to be built from small scripts. For example you can write a small script to look at the player and attach it to every enemies head, add a parameter to limit it to when the player is within
n meters and you’ve got a nice reusable component that anyone (even non programmers) can drop on trees, pickups, bosses, chickens, anything you want.
I want my scripts to be able to be updated
- every frame
- before physics
- after physics
- on a trigger
- on a collisions
Or any combination of these. So I need a mechanism where the script lets the engine know how to use the script.
Rather then screw up my codebase I created a test project to play with LuaBridge. You can get the code here
All of the code is in the one
test.lua is a test script to attach to
GameObjects. It depends on
class.lua (fairly generic class definition based on the lua wiki example) and utility.lua (old code, probably also taken from the lua wiki over the years to manipulate tables).
The code is fairly well commented but here is an overview of how it works.
GameObject is a hollowed out container class for entities in a game. It has a few token members to test exposing them to lua.
LoadScript loads a lua script and executes it. The script is expected to register a global function
register_script that is called returning a class definition (lua table). This definition is instanstiated and attached to the game object. Load script does some simple caching to prevent test.lua being run multiple times.
GameObjects are created with
test.lua attached the GameObjects are ticked. The GameObject::Tick function looks for a function called
tick in it’s lua class and if it’s there calls it.
Once that’s all done, everything is deleted to see if we’re leaking memory.
- really like LuaRef it’s a very nice way to program lua.
- don’t like the way the scripts have to define a callback function, would prefere to return the class definition during the inital script run. However I don’t want to play with the Lua stack and LuaBridge doesn’t seem to provide a clean way to get the table off of the stack.
- In tolua++ you could write and expose a C++ function is such a way as it would appear, in Lua, to return multiple values. This was very nice and Lua-ish (search for
Multiple returned valueshere). I can’t see how to do this in LuaBridge.
Four Character Literal expansion bit me:
1 2 3 4 5 6 7 8
tickfun will ALWAYS be
nil in because clang will convert ‘tick’ in to an integer (note the single quotes, not double quotes for the string
tick). You need to access the table thusly:
to get access to the function.
There is a setting in XCode to warn about this conversion but it’s off by default. Using single quotes is a habit I’ve picked up from Python unfortunately.
Can’t use LuaRef in a std:: container
Because the default constructor for a
LuaRef takes one parameter (the
lua_State that it belongs to) if you try to create a map like:
You will get a compiler error.