tolua++分析


_R 代表LUA_REGISTRYINDEX

在C++中输出一个模块的步骤,如cc.Node
static void extendNode(lua_State* tolua_S)
{
    lua_pushstring(tolua_S,"cc.Node");
    lua_rawget(tolua_S,LUA_REGISTRYINDEX);
    if (lua_istable(tolua_S,-1))
    {
        lua_pushstring(tolua_S,"registerScriptHandler");
        lua_pushcfunction(tolua_S,tolua_cocos2d_Node_registerScriptHandler);
        lua_rawset(tolua_S,-3);
        lua_pushstring(tolua_S,"unregisterScriptHandler");
        lua_pushcfunction(tolua_S,tolua_cocos2d_Node_unregisterScriptHandler);
        lua_rawset(tolua_S, -3);
        lua_pushstring(tolua_S,"scheduleUpdateWithPriorityLua");
        lua_pushcfunction(tolua_S,tolua_Cocos2d_Node_scheduleUpdateWithPriorityLua);
        lua_rawset(tolua_S, -3);
        lua_pushstring(tolua_S,"unscheduleUpdate");
        lua_pushcfunction(tolua_S,tolua_cocos2d_Node_unscheduleUpdate);
        lua_rawset(tolua_S, -3);
        lua_pushstring(tolua_S,"getPosition");
        lua_pushcfunction(tolua_S,tolua_cocos2d_Node_getPosition);
        lua_rawset(tolua_S, -3);
        lua_pushstring(tolua_S, "setContentSize");
        lua_pushcfunction(tolua_S, tolua_cocos2d_Node_setContentSize);
        lua_rawset(tolua_S, -3);
        lua_pushstring(tolua_S, "setAnchorPoint");
        lua_pushcfunction(tolua_S, tolua_cocos2d_Node_setAnchorPoint);
        lua_rawset(tolua_S, -3);
        lua_pushstring(tolua_S, "enumerateChildren");
        lua_pushcfunction(tolua_S, lua_cocos2dx_Node_enumerateChildren);
        lua_rawset(tolua_S, -3);
    }
    lua_pop(tolua_S, 1);
}
向_R中加入函数

int lua_register_cocos2dx_Node(lua_State* tolua_S)
{ 
    tolua_usertype(tolua_S,"cc.Node");
    tolua_cclass(tolua_S,"Node","cc.Node","cc.Ref",nullptr);

    tolua_beginmodule(tolua_S,"Node");
        tolua_function(tolua_S,"addChild",lua_cocos2dx_Node_addChild);
        tolua_function(tolua_S,"removeComponent",lua_cocos2dx_Node_removeComponent);
        tolua_function(tolua_S,"setPhysicsBody",lua_cocos2dx_Node_setPhysicsBody);
        tolua_function(tolua_S,"getDescription",lua_cocos2dx_Node_getDescription);
        tolua_function(tolua_S,"setRotationSkewY",lua_cocos2dx_Node_setRotationSkewY);
        tolua_function(tolua_S,"setOpacityModifyRGB",lua_cocos2dx_Node_setOpacityModifyRGB);
        tolua_function(tolua_S,"setCascadeOpacityEnabled",lua_cocos2dx_Node_setCascadeOpacityEnabled);
        tolua_function(tolua_S,"getChildren",lua_cocos2dx_Node_getChildren);
        //....省略
        tolua_function(tolua_S,"stopAction",lua_cocos2dx_Node_stopAction);
        tolua_function(tolua_S,"getActionManager",lua_cocos2dx_Node_getActionManager);
        tolua_function(tolua_S,"create", lua_cocos2dx_Node_create);
    tolua_endmodule(tolua_S);
    std::string typeName = typeid(cocos2d::Node).name();
    g_luaType[typeName] = "cc.Node";
    g_typeCast["Node"] = "cc.Node";
    return 1;
}

举例:cc.Layer派生与cc.Node,cc.Node派生与cc.Ref

int lua_register_cocos2dx_Layer(lua_State* tolua_S)
{
    tolua_usertype(tolua_S,"cc.Layer");
    tolua_cclass(tolua_S,"Layer","cc.Layer","cc.Node",nullptr);

    tolua_beginmodule(tolua_S,"Layer");
        tolua_function(tolua_S,"create", lua_cocos2dx_Layer_create);
    tolua_endmodule(tolua_S);
    std::string typeName = typeid(cocos2d::Layer).name();
    g_luaType[typeName] = "cc.Layer";
    g_typeCast["Layer"] = "cc.Layer";
    return 1;
}

int lua_register_cocos2dx_Node(lua_State* tolua_S)
{ 
    tolua_usertype(tolua_S,"cc.Node");
    tolua_cclass(tolua_S,"Node","cc.Node","cc.Ref",nullptr);

    tolua_beginmodule(tolua_S,"Node");
        tolua_function(tolua_S,"addChild",lua_cocos2dx_Node_addChild);
        tolua_function(tolua_S,"removeComponent",lua_cocos2dx_Node_removeComponent);
        tolua_function(tolua_S,"setPhysicsBody",lua_cocos2dx_Node_setPhysicsBody);
        tolua_function(tolua_S,"getDescription",lua_cocos2dx_Node_getDescription);
        tolua_function(tolua_S,"setRotationSkewY",lua_cocos2dx_Node_setRotationSkewY);
        tolua_function(tolua_S,"setOpacityModifyRGB",lua_cocos2dx_Node_setOpacityModifyRGB);
        tolua_function(tolua_S,"setCascadeOpacityEnabled",lua_cocos2dx_Node_setCascadeOpacityEnabled);
        tolua_function(tolua_S,"getChildren",lua_cocos2dx_Node_getChildren);
        //....省略
        tolua_function(tolua_S,"stopAction",lua_cocos2dx_Node_stopAction);
        tolua_function(tolua_S,"getActionManager",lua_cocos2dx_Node_getActionManager);
        tolua_function(tolua_S,"create", lua_cocos2dx_Node_create);
    tolua_endmodule(tolua_S);
    std::string typeName = typeid(cocos2d::Node).name();
    g_luaType[typeName] = "cc.Node";
    g_typeCast["Node"] = "cc.Node";
    return 1;
}

上面的代码主要做下列操作:

cc.Layer的元表被设置成cc.Node

cc.Node的元表被设置成cc.Ref

cc.Ref的元表被设置成tolua_commonclass

如果你调用cc.Layer函数,例如对象layer:abc()(layer是一个cc.Layer对象)。layer的元表被成cc.Layer

lua先在cc.Layer中查找abc函数,然后是cc.Node,最后是cc.Ref。

local A={
	__index = A,
	abc=function()
		print('abc')
	end
}
A.__index = A
local B={
	bbb=function()
		print('bbb')
	end
}
B.__index = B
local C=
{
	ccc=function()
		print('ccc')
	end
}
C.__index = C
local obj = {}

setmetatable(B,A)
setmetatable(C,B)
setmetatable(obj,C)
obj:ccc()
obj:bbb()
obj:abc()
tolua++的继承关系和上面的代码一样。


最终tolua++要解决下列问题:

1.已知元表mt取的元表名称_R[mt]

2.已知名称取的原表luaL_getmetatable(L,name)

3.已知元表取继承关系

_R["tolua_super"][mt] = { 

super1 = true,

super2 = true,

...,

}

4.已知一个lua对象,取C++对象.

如果该lua对象是一个userdata,返回userdata,如果是一个表返回表的c_instance

可以使用tolua_isusertype来检查对象是不是给定的类型,例如tolua_isusertype(tolua_S,1,"cc.Ref",0,&tolua_err)检查堆栈1,是不是一个cc.Ref对象.

而cobj = (cocos2d::Ref*)tolua_tousertype(tolua_S,1,0);将取出该对象。

5.tolua.getpeer(target) 取的target的环境.如果等于_R,就返回nil

tolua.setpeer(target,t)设置target的环境,target必须是一个userdata

 例如:

function HomeWork.extend(target)
    local t = tolua.getpeer(target)
    if not t then
        t = {}
        tolua.setpeer(target, t)
    end
    setmetatable(t, HomeWork)
    return target
end

local layer = HomeWork.extend(cc.Layer:create())

对于一个函数的调用顺序是这样的,先t表(layer的环境表)中的,然后到t的元表HomeWork中,其实才是cc.Layer

6.lua对象的绑定

例如:绑定一个场景对象为一个lua对象

 object_to_luaval(tolua_S, "cc.Scene",(cocos2d::Scene*)scene);

template 
void object_to_luaval(lua_State* L,const char* type, T* ret)
{
    if(nullptr != ret)
    {
      
        cocos2d::Ref* dynObject = dynamic_cast(ret);

        if (nullptr != dynObject)
        {
            int ID = (int)(dynObject->_ID) ;
            int* luaID = &(dynObject->_luaID);
            toluafix_pushusertype_ccobject(L,ID, luaID, (void*)ret,type);
        }
        else
        {
            tolua_pushusertype(L,(void*)ret,getLuaTypeName(ret, type));
        }
    }
    else
    {
        lua_pushnil(L);
    }
}

7.对象的释放

对象都从Ref派生,都使用引用计数管理。

~Ref的实现如下:

Ref::~Ref()
{
#if CC_ENABLE_SCRIPT_BINDING
    // if the object is referenced by Lua engine, remove it
    if (_luaID)
    {
        ScriptEngineManager::getInstance()->getScriptEngine()->removeScriptObjectByObject(this);
    }
    else
    {
        ScriptEngineProtocol* pEngine = ScriptEngineManager::getInstance()->getScriptEngine();
        if (pEngine != nullptr && pEngine->getScriptType() == kScriptTypeJavascript)
        {
            pEngine->removeScriptObjectByObject(this);
        }
    }
#endif


#if CC_USE_MEM_LEAK_DETECTION
    if (_referenceCount != 0)
        untrackRef(this);
#endif
}

最后调用toluafix_remove_ccobject_by_refid(_state, pObj->_luaID);和void ScriptHandlerMgr::removeObjectAllHandlers(void* object)


8.tolua_ubox

9.对象创建


用法:创建类元表

_R[mt] = class_name

int tolua_isusertype (lua_State* L, int lo, const char* type, int def, tolua_Error* err)

int lua_isusertype (lua_State* L, int lo, const char* type)

lo必须是一个userdata或者table.(mt是lo的原表),并且lo必须有元表

如果_R[mt] == type ,表示他是一个type 类型数据.

或者_R["tolua_super"][mt]是一个表ST,并且ST[type]如果不为nil或者false,表示lo是type的子类的实例.


static  int lua_isusertable (lua_State* L, int lo, const char* type)

如果_R[lo]==type,返回true


int tolua_fast_isa(lua_State *L, int mt_indexa, int mt_indexb, int super_index)


void tolua_pushusertype_internal (lua_State* L, void* value, const char* type, int addToRoot)

如果存在名称为type的原表mt.

C = mt["tolua_ubox"] or _R["tolua_ubox"]

C[value]

你可能感兴趣的:(lua,c++)