32450新蒲京网站tolua++实现lua层调用c++技术分析

2019-11-30 07:24 来源:未知

tolua++本事剖析 cocos2dx+lua

前言

一直都施用 cocos2dx + lua 实行娱乐开拓,用 Lua 开采能够小心于游戏逻辑的落成,此外一面能够兑现热更新;何况 lua 是三个轻量级的脚本语言,库小但是效率齐全,所以在正经八百非常受招待。此前看了网络海人民广播电视台湾大学有关 c/c++ 如何与 lua 互调的执教,也查阅了 lua 官方网址的 lua api 和 c api,感到大有收获。近年来那后生可畏段时间商量了 tolua++ 里面 lua 层调用 c/c++ 的手艺完结,筹划记录一下学习心得,那样能够让自个儿对 tolua++ 专门的职业体制掌握的更为通畅,也可望自个儿对公理和 api 的剖析能够对别的人有帮带!


tolua++需求将 c/c++ 中的类型,变量,函数,对象导出到lua

  1. 通过 tolua_reg_types(lua_State* tolua_S卡塔尔国将项目导出,功能是为每二个急需导出到 lua 中的 c++ 类型创立元表,比如CCNode 这种类型,就能够在注册表中开创一个元表 CCNode_mt。( 之后会用 _福特Explorer 代表注册表 , _G 代表全局表 , type_mt 表示类型为type的元表。 卡塔尔国

  2. 通过 tolua_cclass (lua_State* L, const char* lname, const char* name, const char* base, lua_CFunction col卡塔尔(قطر‎把基类设为子类的元表;同时在 _R.tolua_super 中以子类的元表为键,成立一张表作为值,而那张表会以基类,基类的基类(递归下去卡塔尔国为键,true/false 为值 ; 还有大概会让基类和子类协同全数平等张tolua_ubox表(以c++指针为键 , fulluserdata为值卡塔尔。 最终让 _G 持有 name_mt,即:_G.lname = name_mt。所以对于多少个 c++ 类型,tolua++ 为其创制的元表最终会让全局表和注册表协同享有。

  3. 通过 tolua_function (lua_State* L, const char* name, lua_CFunction func卡塔尔 将成员方法导出到 步骤1 创制的元表中;即:_G.type_mt.name = func

  4. 通过 tolua_variable(lua_State* L, const char* name, lua_CFunction get, lua_CFunction set卡塔尔国在c++类型对象的元表中思量两张表_G.type_mt.get = {} , _G.type_mt.set = {} ; 两张表以变量名叫键,get/set方法为值。

地点c++数据的导出步骤正是 tolua_Cocos2d_open(lua_State* tolua_S卡塔尔 的落实,在CCLuaStack 领头化的时候做到。

tolua_Cocos2d_open (lua_State* tolua_S卡塔尔(قطر‎内容深入分析

1: tolua_open(tolua_S卡塔尔国 创制生龙活虎体系全局的table

  • _R.tolua_opened = true

  • _R.tolua_value_root = { }

  • _32450新蒲京网站,R.tolua_ubox = { }

  • setmetatable(_R.tolua_ubox,{__mode = v })

  • _R.tolua_super = { }

  • _R.tolua_gc = { }

  • _R.tolua_gc_event = class_gc_event(_R.tolua_gc , _R.tolua_super)

  • _R.tolua_commonclass = { }

  • _G.tolua = { type = tolua_bnd_type , takeownership = tolua_bnd_takeownership , releaseownership = tolua_bnd_releaseownership , cast = tolua_bnd_cast ,isnull = tolua_bnd_isnulluserdata , inherit = tolua_bnd_inherit }

  • 如果lua版本是5.1: _G.tolua.setpeer = tolua_bnd_setpeer ; _G.tolua.getpeer = tolua_bnd_getpeer ;

2: tolua_reg_types (lua_State* tolua_S卡塔尔(英语:State of Qatar) 为急需导出到lua中的c++类型注册元表

  • 对每多少个要导出的c++类型调用tolua_usertype完结元表的注册。跟进tolua_usertype能够开采它做了两件业务。

    Step1: 调用 tolua_newmetatable 创造元表,并且给元表设置大器晚成层层的元方法。
    Step2: 调用 mapsuper( L , derived_type , base_type ) 在tolua_super表中以 derived_mt(子类型的元表)作为三个字段创建一张映射表 t , 那些t以父类,父类的父类(递归下去)的元表为键,布尔变量为值。 用伪代码能够代表为 tolua_super.derived_mt = { base_type = true , base_type_B = true , base_type_C = true} ,那样能够就可以判明五个类的接续关系。

3 tolua_cclass( L , lname , name , base ,col 卡塔尔 达成类之间的涉及,让子类能够三回九转父类

  • mapinheritance(L,derived,base卡塔尔(قطر‎将base设为derived的元表,那样就能够认为derived派生于base.

    1: 内部会调用 set_ubox(L卡塔尔(قطر‎完毕基类与派生类共享同生龙活虎份tolua_ubox表
    2: 然后将基类设置为子类的metatable,借使基类为nil , 就将 _R.tolua_commonclass 设置为子类的元表。

  • mapsuper(L,derived,base卡塔尔(قطر‎这么些办法在地方提到了,便是在 _R.tolua_super 表中开创二个索引表能够用来判别八个类之间是还是不是有继续关系。

    tolua_super.derived_mt = { base_type = true , base_type_B = true , base_type_C = true}

  • push_collector(L,type,col卡塔尔那一个地点的col是个lua_CFunction类型;type_mt.collector = col 将col函数设为type的元表collector字段所对应的元方法。c++ 对象释放的时候会要触发这几个函数。

  • _G.lname = name_mt 最终那个手续正是把前边c++类型在注册表中成立的元表让全局表也兼具意气风发份。

4 接下去正是c++类中的方法和成员变量的导出,就以导出 ccColor3B类中的成员方法和变量 为例子

  • tolua_cclass(tolua_S,"ccColor3B","ccColor3B","",tolua_collect_ccColor3B卡塔尔(قطر‎先将类导出到_G中,何况安装好持续关系.

  • tolua_beginmodule(tolua_S,"ccColor3B"); 将 _G.ccColor3B 压入栈中(那时候lua栈负1地点是ccColor3B_mt,负2位置是_G).

  • tolua_function(tolua_S,"new",tolua_Cocos2d_ccColor3B_new00卡塔尔; 将方法导出到c++类型所对应的元表中即:
    _G.ccColor3B.new = tolua_Cocos2d_ccColor3B_new00

  • tolua_function(tolua_S,"new_local",tolua_Cocos2d_ccColor3B_new00_local);
    _G.ccColor3B.new_local = tolua_Cocos2d_ccColor3B_new00_local 同理上边包车型地铁一各种tolua_function都会将c++方法注册到相应项指标元表中。

  • tolua_variable(tolua_S,"r",tolua_get_ccColor3B_unsigned_r,tolua_set_ccColor3B_unsigned_r)
    tolua_variable(tolua_S,"g",tolua_get_ccColor3B_unsigned_g,tolua_set_ccColor3B_unsigned_g);
    tolua_variable(tolua_S,"b",tolua_get_ccColor3B_unsigned_b,tolua_set_ccColor3B_unsigned_b);

tolua_variable 的逻辑是为每一个档期的顺序创制一张get表,一张set表,然后将变量对应的 get / set 方法放到 get表 / set表中;这样在lua层访问成员变量最后就能索引到对应的存取方法。 即:_G.ccColor3B.get = { "r" = tolua_get_ccColor3B_unsigned_r , "g" = tolua_get_ccColor3B_unsigned_g , "b" = tolua_get_ccColor3B_unsigned_b }

_G.ccColor3B.set = { "r" = tolua_set_ccColor3B_unsigned_r , "g" = tolua_set_ccColor3B_unsigned_g , "b" = tolua_set_ccColor3B_unsigned_b }

tolua++ 胶水函数深入分析 , 照旧以ccColor3B为例

1. tolua_Cocos2d_ccColor3B_new00(lua_State* tolua_S卡塔尔国 将C++对象的指针以full userdata 的样式传播到 lua 层

  • ccColor3B* tolua_ret = (ccColor3B*) Mtolua_new((ccColor3B卡塔尔(قطر‎(卡塔尔(英语:State of Qatar)卡塔尔(قطر‎先创立多少个c++对象,获取到指针。
  • tolua_pushusertype(tolua_S,(void*)tolua_ret,"ccColor3B"卡塔尔 函数在 c++ 层创立对象,然后创造full userdata压入栈中,函数最终会把 userdata 地址重返到lua层,lua 要想操作c++对象就得操作 fulluserdata, 又因为fulluserdata 的元表是 c++对象在lua中的元表,所以最后 lua 正是通过操作c++类型对应的元表来支配c++对象。那也是前方生龙活虎多元步骤的意思。

    压入c++对象时候,以 light userdata 为键,full userdata 为值把那生龙活虎对key-value存入tolua_ubox中。 即:
    ccColor3B_mt.tolua_ubox.tolua_ret = userdata
    setmetatable(userdata,ccColor3B_mt)

2. tolua_Cocos2d_ccColor3B_new00_local 与前者相比超多了四个tolua_register_gc方法,别的的都相通

  • tolua_register_gc : 以c++指针为键,c++类型对应的元表为值,将那对key-value放于_R.tolua_gc中。

3. tolua_get_ccColor3B_unsigned_r(lua_State* tolua_S) 获取ccColor3B类中的r值

  • 先是通过 tolua_tousertype 从栈顶得到userdata中的指针ptr, 把 ptr 转型为(ccColor3B*)
  • 然后将 (lua_Number卡塔尔ptr->r 压入栈中,最终回到给lua层。

总结

  1. tolua++ 为须求导出到lua中的 c++类型 创制元表,那一个元表由 注册表 和 全局表同盟享有,同一时间在元表中注册了意气风发层层元方法。

  2. tolua++ 将父类型设为子类型的元表;父亲和儿子类一齐持有同意气风发份tolua_ubox;同时在tolua_super中为c++类型准备了一张类型映射表,能够因此该表来查询本身有怎样父类。 那样就足以在lua层达成类的后续。

  3. 由此调用 tolua_register_gc 方法,以c++类型的指针为键,c++类型对应的元表为值 作为key-value插入到_R.tolua_gc中 来治本成立c++对象的内部存款和储蓄器。

  4. tolua++ 对 c++ 对象内部存款和储蓄器的拘禁,以及c++对象在lua层的扩充准备放下风流浪漫篇文章再写!
TAG标签:
版权声明:本文由32450新蒲京网站发布于葡萄游戏厅_棋牌游戏,转载请注明出处:32450新蒲京网站tolua++实现lua层调用c++技术分析