- Cocos2dx里Lua与C是怎样交互的?
- 一、Lua2C
- 1.从初始化一个主线程(协程)开始:
- 2.进入register_all_cocos2dx
- 3.进入lua_register_cocos2dx_Ref
今天的面试有被问到Lua与C的调用,一时也没说出个123来,回来抓紧补一下,嘻嘻
Cocos2dx里Lua与C是怎样交互的? 一、Lua2C 1.从初始化一个主线程(协程)开始:
bool LuaStack::init(void)
{
_state = lua_open();
...
register_all_cocos2dx(_state);
...
}
我们注意到了register_all_cocos2dx这个func,主要是注册所有Cocos2dx基本的类到Lua里
2.进入register_all_cocos2dx- tolua_open
注册Cocos方法前的准备工作
TOLUA_API void tolua_open (lua_State* L)
{
int top = lua_gettop(L);
//将tolua_opened压入栈
lua_pushstring(L,"tolua_opened");
//获取LUA_REGISTRYINDEX,然后取栈顶元素k(tolua_open),t[k]入栈顶
lua_rawget(L,LUA_REGISTRYINDEX);
if (!lua_isboolean(L,-1))
{
//压入字符串tolua_opened
lua_pushstring(L,"tolua_opened");
//压入bool值1
lua_pushboolean(L,1);
//获取注册表t,取栈顶bool与字符串tolua_opened,t[tolua_opened]=1
lua_rawset(L,LUA_REGISTRYINDEX);
// create value root table
//压入字符串TOLUA_VALUE_ROOT
lua_pushstring(L, TOLUA_VALUE_ROOT);
//创建table
lua_newtable(L);
//t[TOLUA_VALUE_ROOT] = table
lua_rawset(L, LUA_REGISTRYINDEX);
#ifndef LUA_VERSION_NUM
lua_pushstring(L, "tolua_peers");
lua_newtable(L);
lua_newtable(L);//table1
lua_pushliteral(L, "__mode");
lua_pushliteral(L, "k");
//table1[__model] = k
lua_rawset(L, -3);
//setmetatable(table,table1)
lua_setmetatable(L, -2);
lua_rawset(L,LUA_REGISTRYINDEX);
#endif
......
}
lua_settop(L,top);
}
- tolua_module
TOLUA_API void tolua_module (lua_State* L, const char* name, int hasvar)
{
if (name)
{
lua_pushstring(L,name);
lua_rawget(L,-2);
//判断_G[name]~=nil
if (!lua_istable(L,-1))
{
//弹出刚才的空value
lua_pop(L,1);
//创建空表stack:_G,table
lua_newtable(L);
//压栈name stack:_G,table,name
lua_pushstring(L,name);
//拷贝栈顶-2上面的table stack:_G,table,name,tablecopy
lua_pushvalue(L,-2);
//tablecopy[name] = table stack:_G,table
lua_rawset(L,-4);
}
}
else
{
lua_pushvalue(L,LUA_GLOBALSINDEX);
}
//设置元表的过程
if (hasvar)
{
if (!tolua_ismodulemetatable(L))
{
lua_newtable(L);
tolua_moduleevents(L);
if (lua_getmetatable(L,-2))
lua_setmetatable(L,-2);
lua_setmetatable(L,-2);
}
}
lua_pop(L,1);
}
- tolua_beginmodule
判断这个table的isclass,不是的话返回table;是的话返回他的元表
TOLUA_API void tolua_beginmodule (lua_State* L, const char* name)
{
if (name) { // ... module
//---- now module[name] is a table, get it's metatable to store keys
// get module[name]
lua_pushstring(L,name); // ... module name
lua_rawget(L,-2); // ... module module[name]
// Is module[name] a class table?
lua_pushliteral(L, ".isclass");
lua_rawget(L, -2); // stack: ... module module[name] class_flag
//判断是否是一个class table:isclass == true
if (lua_isnil(L, -1)) {
//返回table
lua_pop(L, 1); // stack: ... module module[name]
return; // not a class table, use origin table
}
lua_pop(L, 1); // stack: ... module class_table
// get metatable
if (lua_getmetatable(L, -1)) { // ... module class_table mt
//返回table的mt
lua_remove(L, -2); // ... module mt
}
//---- by SunLightJuly, 2014.6.5
} else {
lua_pushvalue(L,LUA_GLOBALSINDEX);
}
}
3.进入lua_register_cocos2dx_Ref
- tolua_usertype
TOLUA_API void tolua_usertype (lua_State* L, const char* type)
{
char ctype[128] = "const ";
strncat(ctype,type,120);
//这里创建了两个元表
//执行 与set classname 操作
if (tolua_newmetatable(L,ctype) && tolua_newmetatable(L,type))
//下面分析
mapsuper(L,type,ctype);
}
- mapsuper
设置连个的继承关系
static void mapsuper (lua_State* L, const char* name, const char* base)
{
lua_pushstring(L,"tolua_super");
//获取super
lua_rawget(L,LUA_REGISTRYINDEX);
//注册表R里获取名为name的元表
luaL_getmetatable(L,name);
//获取tolua_super[mt]
lua_rawget(L,-2);
//如果是空的
if (lua_isnil(L,-1))
{
lua_pop(L,1);
lua_newtable(L);
luaL_getmetatable(L,name);
lua_pushvalue(L,-2);
lua_rawset(L,-4);
//相当于super[mt] = table
}
lua_pushstring(L,base);
lua_pushboolean(L,1);
lua_rawset(L,-3);
//基类的k-v 复制到 name元表
luaL_getmetatable(L,base);
lua_rawget(L,-3);
if (lua_istable(L,-1))
{
lua_pushnil(L);
while (lua_next(L,-2) != 0)
{
lua_pushvalue(L,-2);
lua_insert(L,-2);
lua_rawset(L,-5);
}
}
lua_pop(L,3);
}
- tolua_cclass
主要建立父子类的关系
mapinheritance(L,name,base); mapinheritance(L,cname,name); mapsuper(L,cname,cbase); mapsuper(L,name,base);
- tolua_function
注册C方法到栈顶
针对文档、注释、已经一些大哥的帖子做出的自己对于这个过程的注释。
如果哪里有问题,欢迎指正,谢谢。



