在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
打算新项目转到cocos2dx v3上了,下载代码浏览过后发现改动真是非常大,结构性调整很多。 比如tolua绑定这一块,就几乎全翻新了。 胶水代码的生成,改成了全自动式的,通过clang来分析c++代码,可以准确的知道每一个类、函数、参数的信息,再也不用手动写pkg文件了。 运行期对象管理这块,似乎也有了不少改动,至少我原来的一些扩展代码运行不了了,还没来得及细看,待看完再一一录下。 先记录一下目前已看清楚的【类名表、类元表、对象实例】之间的关系: 1、类元表:最核心的表,在lua代码里是不可见的。这是在注册每个类的第一步时建立的:
但其实类元表也就是一个普通的table,只不过它挂在lua registry上,所以说一般的逻辑代码是不会用到它的。类的所有函数、与父类的关系,也都记在这个核心的元表里。 2、类名表:这就是lua代码里要使用该类时所用的名字,也就是:
里cc.Application这个变量对应的表。它是注册类的第二步中建立的:
【类名表】的元表就是【类元表】。 3、对象实例:每个c++ object被push到lua里,是以一个userdata表示。它的元表被设成【类元表】,所对它调用的各种方法都会索引到相应的c++函数上。它的生成是在以下函数中完成:
其实在这里我不是太清楚每个类为什么要有两个表来表示,从功能上说,完全可以合为一个,也就是【类元表】上的所有功能都可以放在【类名表】里实现。也许是因为作者担心类名表存在于普通变量空间里,可能会被无意中修改覆写吧!但分开之后,也明显导致了一些后续处理上的麻烦:比如在给【模块】注册函数时,就要判断当前【模块】是一个【普通模块】(对应于c++里的名字空间)还是一个【类名表】,如果是后者,那函数不能直接挂在它上面,而是要转挂到【类元表】上去,这是在下面函数中处理的: /* Begin module
* It pushes the module (or class) table on the stack
*/
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
if (lua_isnil(L, -1)) {
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
lua_remove(L, -2); // ... module mt
}
//---- by SunLightJuly, 2014.6.5
} else {
lua_pushvalue(L,LUA_GLOBALSINDEX);
}
}
同时这个修改也导致了我之前的一些代码运行失效。因为我会给一些类添加扩展函数,如:
按上述逻辑,实例对象的元表直接指向类元表,也就是说完全绕过了类名表(类名表实际只在创建对象时起个提供类变量的引子作用),而rawset在类名表上的扩展函数自然也被忽略了。 修改办法也很简单,去掉rawset,直接往类名表上写就行了,这会导致其通过元表上的class_newindex_event函数,把数据改记到类元表上,从而符合了实例对象的属性访问流程。 至于之前为什么用一个rawset多此一举?那也是无奈之法,因为上一版本的cocos2dx在lua绑定实现上就是有点问题,不用rawset的话直接就挂了。所以说它现在又改好了,也算是回归自然吧。
|
请发表评论