I have come across the need to use a scripting engine for my C++ game, but after experimenting with many languages since the last few days, nothing has truly stood out as the obvious choice for a language and/or binding library.
I would like have the ability to
- call methods of a specific Game instance from within the scripting language,
- call arbitrary functions in the scripts from C++, and
- test for function existence in the scripts using strings.
Lua looks nice, but I'm unsure of its ability to do 1 and 3. Python and Boost::Python are great, but the same applies. Regardless, here's an example of an ideal implementation.
C++
class Game
{
...
void printNumber(int arg);
};
int main( )
{
Game *game = new Game();
// Make method available to script
functionRegister("printNumber", game->printNumber);
// Test and call function in script
if ( functionExists("greet") )
functionCall("greet", "Hello world");
}
Script pseudocode
function greet( greeting )
print( greeting )
game.printNumber( 42 )
end
The output may be
Hello world
42
Is there a language and library that will pull this off?
Answer
I'm fairly sure Lua can do everything you need relatively simply. I use Lua and C++ in my game. I looked at various wrappers like LuaBind, or using a generator like Swig, but I decided I didn't want any of that stuff and I wrote my own wrapper which I ended up making open source in case other people found it useful.
Using my little library you can do stuff like this in C++:
// Wrap a C++ function
static int Widget_AddChild(lua_State* L)
{
// Typesafe way to extract userdata from Lua
Widget* parent = luaW_check(L, 1);
Widget* child = luaW_check(L, 2);
lua_pushboolean(L, parent->AddChild(child));
}
static luaL_reg Widget_Metatable[] =
{
// Register the function you wrote above
{ "AddChild", Widget_AddChild },
// Widgets also have some getter and setter functions,
// Using these templates you can automatically generate
// wrapper functions for them
{ "GetStyle", luaU_get },
{ "SetStyle", luaU_set },
{ "Style", luaU_getset },
{ NULL, NULL }
};
int luaopen_Widget(lua_State* L)
{
luaW_register(L, "Widget", NULL, Widget_Metatable);
return 1;
}
In lua you could now do something like this:
local w = Widget.new()
w.foo = 10 -- Foo is stored on w, it's not accessible to other instances
-- You can also add values accessible to all Widgets
function Widget.metatable:newfunction()
print(self:GetWidth())
end
w:newfunction()
With all that, you can fairly easily call C++ function from Lua (and vice versa, but I didn't illustrate that here). Once you know how to interact with the Lua API, writing a function to 'safely' call (i.e. call a function only if it exists) a Lua function should be easy as well.
Edit:
If you want to check for the existence of a function before calling it, like I said, just check that the value is a function before calling it.
lua_getglobal(L, "myFunc"); // You can get your function from anywhere, this is just for example
if (lua_isfunction(L, -1)) // Check the top of the stack, make sure it's a function
{
lua_call(L, 0, 0);
}
No comments:
Post a Comment