cocos2d-x内部使用tolua进行lua绑定。可是引擎并没有提供一个通用的接口让我们能够把一个lua函数注冊给C++层面的回调事件。
翻看引擎的lua绑定代码,我们能够仿照引擎中的方法来做。
值得吐槽的是。这套流程在开发中差点儿是不可避免的,而cocos2d-x居然不把它作为一个公用接口暴露给开发人员,而须要我自己动手,真是无奈。
以下以一个简单的消息分发类为样例,演示怎样完毕这一工作。
MessageDispatcher.h
class MessageDispather { public: static MessageDispather* sharedDispather(); public: void invokeLuaCallbackFunction(int msgId, const char* text); void registerScriptHandler(int nHandler); private: int mLuaHandlerId; };
MessageDispatcher.cpp
#include "CCLuaEngine.h" MessageDispather* sharedDispather() { static MessageDispather* instance = NULL; if(instance == NULL) instance = new MessageDispather(); return instance; } void MessageDispather::invokeLuaCallbackFunction(int msgId, const char* text) { if(mScriptHandler > 0) { CCLuaStack* stack = CCLuaEngine::defaultEngine()->getLuaStack(); stack->pushInt(msgId); stack->pushString(text); stack->executeFunctionByHandler(mScriptHandler, 2); stack->clean(); } } void MessageDispather::registerScriptHandler(int nHandler) { mLuaHandlerId = nHandler; }
说明
#include "CCLuaEngine.h"
这个头文件来自cocos2d-x\scripting\lua\cocos2dx_support
整个目录里的内容是cocos2d-x引擎做lua绑定时封装的一些工具类。
你须要在你的项目中加入这个文件夹的include搜索路径。
void registerScriptHandler(int nHandler)
这个函数须要暴露给lua。
在lua中调用这个函数。參数nHandler的位置传进去一个lua函数。就行在C++这边得到一个nHandler的整数句柄值。
之后不论什么时间假设想要在C++中调用刚刚注冊的lua回调函数,须要以这个整数值来指代那个函数。
void invokeLuaCallbackFunction(int msgId, const char* text)
在C++用调用此函数,我们期待它会调用到一个在lua中定义的回调函数。
详细这个函数里的实现是什么意思,假设你对lua c api有一定了解的话应该非常easy能看懂,我就不再做解释。
用于tolua的pkg文件
class MessageDispather { static MessageDispather* sharedDispather(); void registerScriptHandler(LUA_FUNCTION nHandler); };
在lua中使用MessageDispatcher
local function onMessage(msgId, text) print(msgId, text) end MessageDispatcher:sharedDispatcher():registerScriptHandler(onMessage)
万事大吉。。。。。才怪!
有没有发现我们的pkg文件里有一个类型是LUA_FUNCTION
??
对,由于这个參数在lua中应该传入一个函数。而到了C++这边我们拿到的却是一个int。
这并非tolua的缺省行为,而是cocos2d-x针对这样的情况做的一个特殊处理。
翻看cocos2d-x的tolua绑定流程,我们能够发现build.bat中的内容是这种:
tolua++ -L basic.lua -o "../../scripting/lua/cocos2dx_support/LuaCocos2d.cpp"
Cocos2d.pkg
这里basic.lua是一些额外的逻辑,当中处理LUA_FUNCTION类型的逻辑也在里面。
那么我们能够照猫画虎,请创建这样一个lua文件:
_is_functions = _is_functions or {} _to_functions = _to_functions or {} -- register LUA_FUNCTION, LUA_TABLE, LUA_HANDLE type _to_functions["LUA_FUNCTION"] = "toluafix_ref_function" _is_functions["LUA_FUNCTION"] = "toluafix_isfunction" _to_functions["LUA_TABLE"] = "toluafix_totable" _is_functions["LUA_TABLE"] = "toluafix_istable" local toWrite = {} local currentString = ‘‘ local out local WRITE, OUTPUT = write, output function output(s) out = _OUTPUT output = OUTPUT -- restore output(s) end function write(a) if out == _OUTPUT then currentString = currentString .. a if string.sub(currentString,-1) == ‘\n‘ then toWrite[#toWrite+1] = currentString currentString = ‘‘ end else WRITE(a) end end function post_output_hook(package) local result = table.concat(toWrite) local function replace(pattern, replacement) local k = 0 local nxt, currentString = 1, ‘‘ repeat local s, e = string.find(result, pattern, nxt, true) if e then currentString = currentString .. string.sub(result, nxt, s-1) .. replacement nxt = e + 1 k = k + 1 end until not e result = currentString..string.sub(result, nxt) if k == 0 then print(‘Pattern not replaced‘, pattern) end end replace([[*((LUA_FUNCTION*)]], [[(]]) replace([[tolua_usertype(tolua_S,"LUA_FUNCTION");]], [[]]) WRITE(result) end
然后在你运行tolua++的时候把这个文件作为-L參数传进去就能够了。