Embedding Lua into a C++ engine
Scripting languages are very useful things to have in a game engine. It allows the developer to offload content-related programming (AI, animation, UIs) to junior programmers and also make the system more dynamic since the developer no longer needs to recompile + redistribute the game after changing one line of AI or UI code.
For example, instead of writing this in C++:
Sprite* s = new Sprite("Character.png");
s->setPos(10,20);
I’d prefer to write this in Lua:
local s = Sprite("Character.png")
s:setPos(10,20)
so that I wouldn’t need to re-compile every time I changed the sprite name or position. The ideal method utilizes a data-driven design with exporter tools, but I’m going to ignore it for now because it is loads more work and requires writing parsers and complex exporters.
Integrating Lua is quite easy and only requires 3 components:
- Lua (download binary distribution)
- tolua++ (comes in source only)
- A C++ engine - preferably you know what C++ classes you wish to expose to the scripting language.
For Lua to be able to access C++ classes directly we use tolua++ to create binding code between C++ and Lua. Without tolua++ this binding needs to be coded by hand, but luckily tolua++ can autogenerate it via .pkg files.
So, if I wanted to expose the Sprite class to Lua I would first create a Sprite.pkg - something like this:
namespace MyGame
{
class Sprite
{
public:
Sprite(std::string filename);
void setPos(Ogre::Vector2 pos);
Ogre::Vector2 getPos();
};
}
#endif
Notice how the .pkg is similar to C++ header files. They are exactly C++ header files with private and protected variables and methods removed. You can use any C++ class you wish in .pkg as long as you provide a definition of it somewhere else. In the above example, I use Ogre’s Vector2 - which I would define in another .pkg called OgreVectors.pkg then connect all the packages into one called All.pkg like this:
$#include "required.h" $pfile "Sprites.pkg" $pfile "OgreVectors.pkg"
Then I would run tolua++ on the command line:
"tolua++.exe" -o Bindings.cpp -H Bindings.h All.pkg
The output would be Bindings.cpp and Bindings.h which you copy to your game engine’s source and include directories. In your C++ code you write the following:
#include "Bindings.h"
lua_State* lua = lua_open();
tolua_MyGameSprites_open(lua);
int s = luaL_loadfile(lua, "myscript.lua");
if(s == 0)
{
s = lua_pcall(lua, 0, LUA_MULTRET, 0);
}
report_errors(lua, s);
Where report_errors is:
void report_errors(lua_State* lua, int status)
{
if ( status!=0 )
{
std::string s = lua_tostring(lua, -1);
std::cerr << "-- " << s << std::endl;
lua_pop(lua, 1);
}
}
And that’s it! You can call any Lua script and use the C++ classes as if they were native in Lua!
There are many alternative scripting languages to Lua, but none as easy to integrate as Lua. The following are used in a variety of games and game engines. I suggest you look at them if you don’t like the syntax of Lua or don’t use C++ classes extensively.
- Python + boost::python
- Lua via Luabind
- Lua via easyLua
- Squirrel
- Squirrel via SQPlus
- AngelScript
- SpiderMonkey / JavaScript /ECMAScript
- Ruby
- GameMonkey
Add comment May 26th, 2007