[cocos2dx] lua注冊回調到c++


思路

像所有語言一樣,綁定回調主要是執行的任務執行到特定情形的時候,調用對用回調方法。 這里也一樣。核心思路是,當c代碼執行到特定特定情形的時候,調用lua的方法

我這里使用的是用lua_stack直接調用lua的方法,沒有使用cocos2dx封裝的那個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里可調用的接口的,需要手動編寫綁定方法

      說這個得用到cocos2dx中提供的一個方法 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 方法調用 代碼就不寫了


疑惑

包括cocos2dx里的所有lua擴展(不是通過腳本直接生成lua接口的)都是通過注冊表里擴展的 lua_rawget(tolua_S, LUA_REGISTRYINDEX); 我沒完全看完lua里的userdata綁定過程,封裝的太深了。

疑惑是綁定了以后也是userdata,但是擴展的時候拿到都是table。按我已看到的代碼是userdata綁定到global表里的。這里的實現機制怎么回事,知道的,望不吝指點

 

 

轉載請注明出處(http://www.cnblogs.com/boliu/p/4091274.html)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM