之前介绍了在 C/C++ 中如何调用 Lua 函数, 但是那种方法并不灵活, 它依赖于 Lua 函数的名字. 在不考虑获取函数返回值的情况下, 使用一种事件驱动的模型来与 Lua 代码交互会更便于维护和扩展.
如果要使用事件驱动模型的话, 那么它的过程应该是: 由 C/C++ 代码触发事件, 然后发送给 Lua 代码, 由 Lua 执行相应的功能. 这里就需要一个"媒介", 通过它来统一事件触发函数和事件处理函数(类似 MFC 中的控件 ID).
那来看看怎么设计这个事件驱动模型. 首先, 提供一个 LuaGlue 函数来设定在 Lua 脚本中的事件处理程序.
Copy LuaGlue _RegisterEvent(lua_State * L) {
g_strEventHandle = g_lua . GetStringArgument ( 1 , "" );
return 0 ;
}
那么, 再来设计发送事件函数.
Copy void FireEvent( int nId , const char* args) {
if (g_strEventHandle != "" ) {
char buf[ 256 ];
if (args) {
sprintf_s(buf , 255 , "%s(%d, %s)" , g_strEventHandle . c_str() , nId , args) ;
} else {
sprintf_s(buf , 255 , "%s(%d)" , g_strEventHandle . c_str() , nId) ;
}
g_lua . RunString (buf);
}
}
第一个参数是事件ID, 这个很好理解, 那第二个参数是什么? 因为 Lua 是支持变参系统的, 所以我们可以为每个事件设定不同的参数, 而第二个参数是用来表示那些可变参数的.
接下来, 看看 Lua 事件处理函数的模板:
Copy local EVENT_SAMPLE = 1000
RegisterEvent ( "EventHandle" )
function EventHandle ( nId , ...)
if nId == EVENT_SAMPLE then
print ( "Sample Event!" )
for i, v in ipairs { ... } do
print (v)
end
end
end
现在, 我们在 C/C++ 的主程序中发出事件, 看看会输出什么:
Copy #define EVENT_SAMPLE 1000
cLua g_lua;
g_lua . RunScript ( "C:\\Users\\Administrator\\Desktop\\test.lua" );
FireEvent(EVENT_SAMPLE , "\"你好\", 10" ) ;
看! 一个基于 C/C++ 和 Lua 的事件驱动模型建立起来了. 这个系统需要注意的地方在于, Lua 代码和 C/C++ 代码需要对事件 ID 和传递的参数的含义保持一致.
下面是完整的 C/C++ 端代码:
Copy std :: string g_strEventHandle = "" ;
cLua g_lua;
LuaGlue _RegisterEvent(lua_State * L) {
g_strEventHandle = g_lua . GetStringArgument ( 1 , "" );
return 0 ;
}
void FireEvent( int nId , const char* args) {
if (g_strEventHandle != "" ) {
char buf[ 256 ];
if (args) {
sprintf_s(buf , 255 , "%s(%d, %s)" , g_strEventHandle . c_str() , nId , args) ;
} else {
sprintf_s(buf , 255 , "%s(%d)" , g_strEventHandle . c_str() , nId) ;
}
g_lua . RunString (buf);
}
}
#define EVENT_SAMPLE 1000
int _tmain( int argc , _TCHAR * argv[]) {
g_lua . AddFunction ( "RegisterEvent" , _RegisterEvent);
g_lua . RunScript ( "C:\\Users\\Administrator\\Desktop\\test.lua" );
FireEvent(EVENT_SAMPLE , "\"你好\", 10" ) ;
system( "PAUSE" ) ;
return 0 ;
}