在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
第一层:纯C环境下,把C函数注册进Lua环境a.lua 文件 print(foo(99)) a.c 文件 #include <lua.h> #include <lualib.h> #include <lauxlib.h> int foo(lua_State *L) { int n = lua_tonumber(L, 1); lua_pushnumber(L, n + 1); return 1; } int main() { lua_State *L = lua_open(); luaL_openlibs(L); lua_register(L, "foo", foo); luaL_dofile(L, "a.lua"); lua_close(L); return 0; } 看完上面那段代码,再解释起来就容易多了: 1、要想注册进Lua环境,函数需要定义为这个样: 第二层:在cocos2d-x环境下,把C函数注册进Lua环境1、在AppDelegate.cpp文件中的关键代码如下: LuaStack* stack = engine->getLuaStack(); LuaStack* stack = engine->getLuaStack(); lua_State *L = stack->getLuaState(); lua_register(L, "test_lua_bind", test_lua_bind); 2、接下来,找个地方把 int test_lua_bind(lua_State *L) { int number = lua_tonumber(L, 1); number = number + 1; lua_pushnumber(L, number); return 1; } 3、大功告成,现在就可以在main.lua文件里使用 local i = test_lua_bind(99) print("lua bind: " .. tostring(i)) 4、如果是新建一个.c文件呢?把 #include "test_lua_bind.h" 在 extern "C" { #include "lua.h" #include "lualib.h" } int test_lua_bind(lua_State *L); 再创建 #include "test_lua_bind.h" int test_lua_bind(lua_State *L) { int number = lua_tonumber(L, 1); number = number + 1; lua_pushnumber(L, number); return 1; } cocos2d-x项目没有使用Makefile,而是非常聪明地使用了与具体环境相关的工程文件来作为命令行编译的环境,比如在编译iOS或Mac时就使用Xcode工程文件,在编译Android时就使用 所以,添加好了 把 第四层:在纯C++环境下,使用toLua++来把一个C++类注册进Lua环境使用toLua++的标准做法是: 1、准备好自己的C++类,该怎么写就怎么写 toLua++这种自己手写.pkg文件的方式古老又难受,所以我没有仔细地去学习,这套流程放在10年前的那个年代是没有太大问题的,作者怎么规定就怎么用好了,但是放在2014年的今天,任何程序的架构设计都讲究学习成本低、轻量化、符合以往的习惯,因此toLua++用起来我觉得其实是难受的。 下面我以尽量最少的代码来走一遍toLua++的流程,注意这是在纯C++环境下,跟任何框架都没关系,也不考虑内存释放等细节: MyClass.h class MyClass { public: MyClass() {}; int foo(int i); }; MyClass.cpp #include "MyClass.h" int MyClass::foo(int i) { return i + 100; } MyClass.pkg class MyClass { MyClass(); int foo(int i); }; MyLuaModule.h extern "C" { #include "tolua++.h" } #include "MyClass.h" TOLUA_API int tolua_MyLuaModule_open(lua_State* tolua_S); MyLuaModule.pkg $#include "MyLuaModule.h" $pfile "MyClass.pkg" main.cpp extern "C" { #include <lua.h> #include <lualib.h> #include <lauxlib.h> } #include "MyLuaModule.h" int main() { lua_State *L = lua_open(); luaL_openlibs(L); tolua_MyLuaModule_open(L); luaL_dofile(L, "main.lua"); lua_close(L); return 0; } main.lua local test = MyClass:new() print(test:foo(99)) 先在命令行下执行: tolua++ -o MyLuaModule.cpp MyLuaModule.pkg 此命令用来生成桥接文件MyLuaModule.cpp。注意命令行中-o参数的顺序不能随意摆放,从这个小事也能看出tolua++的古老和难用 生成好MyLuaModule.cpp文件后,就能看到它里面的那一大堆桥接代码了,比如 至此,对toLua++的运作原理心里就透亮了,无非就是: 1、把自己该写的类写好 第五层:使用cocos2d-x的方式来将C++类注册进Lua环境bindings-generator脚本的工作机制是: 1、不用挨个类地写桥接.pkg和.h文件了,直接定义一个ini文件,告诉脚本哪些类的哪些方法要暴露出来,注册到Lua环境里的模块名是什么,就行了,等于将原来的每个类乘以3个文件的工作量变成了所有类只需要1个.ini文件 bindings-generator脚本掌握了生成toLua++桥接代码的主动权,不仅可以省下大量的.pkg和.h文件,而且可以更好地插入自定义代码,达到cocos2d-x环境下的一些特殊目的,比如内存回收之类的。所以cocos2d-x从3.x开始放弃了toLua++和.pkg而改用了自己写的bindings-generator脚本是非常值得赞赏的聪明做法。 接下来说怎么用bindings-generator脚本: 1、写自己的C++类,按照cocos2d-x的规矩,继承cocos2d::Ref类,以便使用cocos2d-x的内存回收机制。当然不这么干也行,但是不推荐,不然在Lua环境下对象的释放狠麻烦。 看着步骤挺多,其实都狠简单。下面一步一步来。 首先是自定义的C++类。我习惯将文件保存在 frameworks/runtime-src/Classes/MyClass.h #include "cocos2d.h" using namespace cocos2d; class MyClass : public Ref { public: MyClass() {}; ~MyClass() {}; bool init() { return true; }; CREATE_FUNC(MyClass); int foo(int i); }; frameworks/runtime-src/Classes/MyClass.cpp #include "MyClass.h" int MyClass::foo(int i) { return i + 100; } 然后编写.ini文件。在 frameworks/cocos2d-x/tools/tolua/MyClass.ini [MyClass] prefix = MyClass target_namespace = my headers = %(cocosdir)s/../runtime-src/Classes/MyClass.h classes = MyClass 也即在MyClass.ini中指定MyClass.h文件的位置,指定要暴露出来的类,指定注册进Lua环境的模块名。 注意,这个地方我踩了个坑。如果.ini配置文件中存在 然后修改 frameworks/cocos2d-x/tools/tolua/genbindings.py cmd_args = {'cocos2dx.ini' : ('cocos2d-x', 'lua_cocos2dx_auto'), \ 'MyClass.ini' : ('MyClass', 'lua_MyClass_auto'), \ ... (其实这一步本来是可以省略的,只要让genbindings.py脚本自动搜寻当前目录下的所有ini文件就行了,不知道将来cocos2d-x团队会不会这样优化) 至此,生成桥接文件的准备工作就做好了,执行genbindings.py脚本: python genbindings.py (在Mac系统上可能会遇到缺少yaml、Cheetah包的问题,安装这些Python包狠简单,先 成功执行genbindings.py脚本后,会在 每次执行genbindings.py脚本时间都挺长的,因为它要重新处理一遍所有的.ini文件,建议大胆修改脚本文件,灵活处理,让它每次只处理需要的.ini文件就可以了,比如像这个样子: 在 编辑 然后在正确的代码位置加入对 最后在执行编译前,将新加入的这几个C++文件都加入到Xcode工程中,使得编译环境知道它们的存在: 这其中还有一个小坑,由于 最后,就可以用 修改main.lua文件中,尝试调用一下MyClass类: local test = my.MyClass:create() print("lua bind: " .. test:foo(99))
register_all_cocos2dx_xxx(lua_State* tolua_S) 函数的 tolua_module(tolua_S,nullptr,0); 下面增加包名 tolua_module(tolua_S,"xxx",0); 结尾处多写一条 tolua_endmodule(tolua_S);
2. 接上面增加了lua包名后,生成binding文件会报错 conversion wasn't set in 'ns_map' section of the conversions.yaml 修改 frameworks/cocos2d-x/tools/bindings-generator/targets/conversions.yaml 在 ns_map下增加一条新的包名信息 "c++命名空间::": "lua包名." |
请发表评论