cocos2d tolua C++对象使用lua对象的变量,函数

前端之家收集整理的这篇文章主要介绍了cocos2d tolua C++对象使用lua对象的变量,函数前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

C++对象绑定到lua通常是创建一个userdata用来存放cpp对象。在tolua库中维护了一张表:tolua_uBox表,它是个弱表,用来缓存所有cppobj的ptr->userdata映射。

userdata对象的生成过程和cpp对象到userdata的映射的生成

void tolua_pushusertype_internal (lua_State* L,void* value,const char* type,int addToRoot)
{
if (value == NULL)
lua_pushnil(L);
else
{
luaL_getMetatable(L,type); /* stack: mt */
if (lua_isnil(L,-1)) { /* NOT FOUND Metatable */
lua_pop(L,1);
return;
}
lua_pushstring(L,"tolua_uBox");
lua_rawget(L,-2); /* stack: mt uBox */

//现在每个Metatable都维护了一份tolua_uBox表,在类的生成过程,就会为Metatable生成这个tolua_uBox表,具体请看mapinheritance和set_uBox
if (lua_isnil(L,-1)) {
lua_pop(L,1);
lua_pushstring(L,"tolua_uBox");
lua_rawget(L,LUA_REGISTRYINDEX); 在创建tolua环境就会创建注册表中的tolua_uBox
};

lua_pushlightuserdata(L,value); /* stack: mt uBox key<value> */
lua_rawget(L,-2); /* stack: mt uBox uBox[value] */
//查看在mt中的uBox表中是否存在value(C++对象),如果不存在,创建一个,并设置值为userdata,值为value。
if (lua_isnil(L,-1))
{
lua_pop(L,1); /* stack: mt uBox */
lua_pushlightuserdata(L,value);
*(void**)lua_newuserdata(L,sizeof(void *)) = value; /* stack: mt uBox value newud */

//newud就是userdata
lua_pushvalue(L,-1); /* stack: mt uBox value newud newud */
lua_insert(L,-4); /* stack: mt newud uBox value newud */
lua_rawset(L,-3); /* uBox[value] = newud,stack: mt newud uBox */ 映射
lua_pop(L,1); /* stack: mt newud */
/*luaL_getMetatable(L,type);*/
lua_pushvalue(L,-2); /* stack: mt newud mt */
lua_setMetatable(L,-2); /* update mt,stack: mt newud */ 设置userdata的Metatable为cpp的Metatable。

#ifdef LUA_VERSION_NUM
lua_pushvalue(L,TOLUA_NOPEER); /* stack: mt newud peer */
lua_setfenv(L,-2); /* stack: mt newud */ 设置userdata的环境为TOLUA_NOPEER
#endif
}
else
{
//.....
}
}

那这和C++对象使用lua对象的函数,变量有什么关系呢?

其实一直在纠结lua对象继承C++对象的这个问题,到今天才看到比较满意的解决办法。

function cls.extend(target,...) //target是个C++对象来的
-- 先继承C++对象
local t = tolua.getpeer(target)
if not t then
t = {}
tolua.setpeer(target,t)
end
setMetatable(t,cls)
cls.ctor(target,...)
return target
end

在网上其实存在很多这个例子。

知其然不知其然怎么行呢?

tolua_getpeer和tolua_setpeer是什么鬼:

static int tolua_bnd_getpeer(lua_State* L) {


/* stack: userdata */
lua_getfenv(L,-1);
if (lua_rawequal(L,-1,TOLUA_NOPEER)) { 在上面的描述中,userdata的环境就是TOLUA_NOPEER,所以这边会返回空
lua_pop(L,1);
lua_pushnil(L);
};
return 1;
};


static int tolua_bnd_setpeer(lua_State* L) {


/* stack: userdata,table */
if (!lua_isuserdata(L,-2)) {
lua_pushstring(L,"Invalid argument #1 to setpeer: userdata expected.");
lua_error(L);
};


if (lua_isnil(L,-1)) {


lua_pop(L,1);
lua_pushvalue(L,TOLUA_NOPEER);
};
lua_setfenv(L,-2); 为userdata设置新的环境


return 0;
};


所以例子中的

local t = tolua.getpeer(target)
if not t then
t = {}
tolua.setpeer(target,t)
end

这段是为了给这个C++对象(userdata)设置一个新的环境。这个环境现在什么都没有

setMetatable(t,cls) 现在这个环境中有了cls,这个cls就是Lua table。可以看做是我们的lua对象,lua class

然后返回C++对象。这样就可以通过C++对象使用到lua对象中的所有内容。其实在lua文件中可以创建这样的C++对象,既可以使用这个对象原有的东西还可以使用我们的lua内容,其实换个思路想想,如果把返回的对象看做是lua对象,这也就是lua对象继承C++对象嘛。


范例:

local tt = cc.Node:create()
local env = {}
env.abc = 4
env.func = function()
print("环境函数") //输出环境函数 end local peer = tolua.getpeer(tt) if not peer then tolua.setpeer(tt,env) print(tt.abc) //输出4 tt.func() end

原文链接:https://www.f2er.com/cocos2dx/340050.html

猜你在找的Cocos2d-x相关文章