您的位置:首页 > 移动开发 > Cocos引擎

cocos2d-x 2.2.0 如何在lua中注册回调函数给C++

2014-12-02 11:20 295 查看
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有一定了解的话应该很容易能看懂,我就不再做解释。


用于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参数传进去就可以了。

到这里,应该就可以正常生成了。

当时我遇到了运行时出现错误的情况。

修改成这样就没有问题了

LUA_FUNCTION luaCallback = toluafix_ref_function(tolua_S,2,0);

主要是自动生成的回调函数等号右边会出现强制类型转换,但是这样就会报错

把这个去掉就可以了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: