Lua注册回调到C++

思路

像所有语言一样,绑定回调主要是执行的任务执行到特定情形的时候,调用对用回调方法。 本文也一样,Lua注册回调到C++的核心思路是,当C代码执行到特定特定情形的时候,调用Lua的方法。


我这里使用的是用lua_stack直接调用lua的方法,没有使用Cocos2d-x封装的那个dispatcher,因为熟悉那个格式太墨迹了。


主要步骤如下


缓存Lua函数在Lua环境中的引用


在C代码的地方用C的方式设置好回调


在C代码回调函数执行的时候,调用lua函数


实现


C代码绑定回调,调用Lua函数


void ArmatureNode::registerMovementEventHandler(int handler)
{
    unregisterMovementEventHandler();  //移除之前注册的监听
    _movementHandler = handler;         //缓存lua函数的引用 这个后边说
     
    auto dispatcher = getCCEventDispatcher();
     
    auto f = [this](cocos2d::EventCustom *event) //注册c代码形式的回调 这里用function做
    {
        auto eventData = (dragonBones::EventData*)(event->getUserData());
        auto type = (int) eventData->getType();
        auto movementId = eventData->animationState->name;
        auto lastState = eventData->armature->getAnimation()->getLastAnimationState();
         
        auto stack = cocos2d::LuaEngine::getInstance()->getLuaStack();
        stack->pushObject(this, "db.ArmatureNode");
        stack->pushInt(type);
        stack->pushString(movementId.c_str(), movementId.size());        
        //通过LuaStack调用lua里的函数    最后一个参数设置参数个数
        stack->executeFunctionByHandler(_movementHandler, 3);
    };
     
    dispatcher->addCustomEventListener(dragonBones::EventData::COMPLETE, f);
}
void ArmatureNode::unregisterMovementEventHandler(void)
{
    if (0 != _movementHandler)
    {
        cocos2d::LuaEngine::getInstance()->removeScriptHandler(_movementHandler); //移除lua函数的绑定
        _movementHandler = 0;
    }
}
提供Lua函数绑定到C的方法   


上边的这个函数直接用cocos里的genbinding.py 是无法正确生成Lua里可调用的接口的,需要手动编写绑定方法.


说这个得用到Cocos2d-x中提供的一个方法:toluafix_ref_function会把一个Lua栈中的方法转成一个int,以便C++中调用。我会在最后面说这个


int tolua_db_DBCCArmature_registerMovementEventHandler(lua_State* tolua_S)
{
    if (NULL == tolua_S)
        return 0;
    int argc = 0;
     
    dragonBones::ArmatureNode* self = nullptr;
    self = static_cast<dragonBones::ArmatureNode*>(tolua_tousertype(tolua_S,1,0)); //第一个参数 就是lua里的self
     
    argc = lua_gettop(tolua_S) - 1;
     
    if (1 == argc)
    {
        //第二个参数,就是Lua里的function 这里要通过toluafix_ref_function这个函数映射成一个Int值
        int handler = (toluafix_ref_function(tolua_S,2,0)); 
        self->registerMovementEventHandler(handler);
         
        return 0;
    }
    return 0;
}
 


将绑定方法绑定到Lua环境里


int extends_ArmatureNode(lua_State* tolua_S)
{
    lua_pushstring(tolua_S, "db.ArmatureNode");//之前db.ArmatureNode是通过脚本绑定在lua里。这里只做扩展
    lua_rawget(tolua_S, LUA_REGISTRYINDEX);
    if (lua_istable(tolua_S,-1))
    {
        lua_pushstring(tolua_S,"registerMovementEventHandler");
        lua_pushcfunction(tolua_S,tolua_db_DBCCArmature_registerMovementEventHandler);
        lua_rawset(tolua_S,-3);
    }
     
    lua_pop(tolua_S, 1);
    return 0;
}
Lua里设置回调到C++


 local arm = db.ArmatureNode:create("Dragon")
    local animation = arm:getAnimation()
    animation:gotoAndPlay("walk")
    arm:registerMovementEventHandler(
        function(...)
            print(...) 
        end
    )




-测试


打印回调输出,测试通过 userdata 8 walk

其他


toluafix_ref_function 以及 toluafix_get_function_by_refid


这两个方法是相互对应的 toluafix_ref_function这个方法在注册表上将一个lua的function与一个function_id生成映射 toluafix_get_function_by_refid 方法可以通过前一个方法生成的function_id来讲绑定的lua function放到栈顶


//
TOLUA_API int toluafix_ref_function(lua_State* L, int lo, int def)
{
    if (!lua_isfunction(L, lo)) return 0;
    s_function_ref_id++;                            //function_id 加1
    lua_pushstring(L, TOLUA_REFID_FUNCTION_MAPPING);//在注册表上,存放luafunction 映射table 的key压栈
    lua_rawget(L, LUA_REGISTRYINDEX);               //获取方法映射表,放在栈顶
    lua_pushinteger(L, s_function_ref_id);          //function_id压栈
    lua_pushvalue(L, lo);                           //lo有效处索引处是lua方法,lua方法拷贝,压栈
 
 
    lua_rawset(L, -3);                        //生成映射 
    lua_pop(L, 1);                                              
    return s_function_ref_id;
}
TOLUA_API void toluafix_get_function_by_refid(lua_State* L, int refid)
{
    lua_pushstring(L, TOLUA_REFID_FUNCTION_MAPPING);            //存放luafunction 映射table 的key压栈
    lua_rawget(L, LUA_REGISTRYINDEX);                           //获取方法映射表,放在栈顶
    lua_pushinteger(L, refid);                                  //function_id压栈
    lua_rawget(L, -2);                                          //获取到的luafunction 放到栈顶
    lua_remove(L, -2);                                          //
}
executeFunctionByHandler


executeFunctionByHandler 这个方法只是通过toluafix_get_function_by_refid 获取到function然后通过lua_pcall 方法调用,代码就不写了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值