1. 程式人生 > >cocos2d-x 2.2.0 怎樣在lua中註冊回調函數給C++

cocos2d-x 2.2.0 怎樣在lua中註冊回調函數給C++

s2d 意思 函數 mlu pan build [[]] 進行 ret

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參數傳進去就能夠了。

應該真的萬事大吉了。



cocos2d-x 2.2.0 怎樣在lua中註冊回調函數給C++