本文主要来自小塔博客这篇文章http://www.zaojiahua.com/binding-custom-classes.html 该文详细清晰地讲述cocos2d-x Lua的一个重要功能,就是Lua读取C++类,用C++类写lua不方便实现的功能,用lua来读取,但是该文是在xcode环境下讲述的,没有说VS怎么配置,其实都差不多,我就转来修改下
我们的需求是:在c++层定义了一些类,我们需要将这些类导出给Lua来使用,从而完成在c++层实现起来容易的需要,这个时候就需要将整个类作为模块导出。而Cocos2d-x正是采用的这种思想,将Cocos中的类导出供用户使用,而不是再写一套Lua代码,用户使用Cocos导出的这套接口,在Lua脚本层写游戏代码。为了更好的理解这部分的内容,可以先看一下在Lua中调用c++函数这篇博客,了解c++中调用Lua的机制。该博客中我们将c++中需要导出的函数放到了一个模块中,其中我们手动的做了一些工作。然而Lua的本质是C,不是C++,Lua提供给C用的API也都是基于面向过程的C函数来用的,要把C++类注册进Lua形成一个一个的table环境是不太容易一下子办到的事。为了实现我们的需求,同样也是官方的需求,在Cocos 2.x版本的时候,使用的是tolua++这个工具,但是这个工具用起来相当的麻烦,耗费体力,所以现在使用的是bindings-generator工具(官方用Python写的一个工具),这个东西底层使用的也应该是tolua++。
我没有使用过tolua++这个工具,不过从网上了解了一下这个工具的使用方法,大致是这样的:1、写自己的c++类,该怎么写就怎么写。2、根据需要导出的c++类的头文件写对应的.pkg文件,具体怎么写得参照tolua++格式。3、写一个桥接的类,只写它的头文件,cpp文件是使用tolua++工具来生成的,头文件具体怎么写,也是需要按照tolua++的格式。4、给这个桥接的类写一个.pkg文件。5、使用命令生成桥接类的.cpp文件。6、程序中使用桥接的类,执行一些先关的函数。所以如果使用的是tolua++工具的话,至少需要写三个文件,导出类的.pkg文件,桥接类的.h文件,桥接类的.pkg文件,可想而知还是比较麻烦的。现在好了,我们有了bindings-generator工具,下面就来具体的使用一下吧。
1、使用Cocos Code IDE建立一个Lua工程,我用的是2.0版,右击工程 Cocos Tool ->选中add native code这个选项,这样会在工程目录下生成frameworks这个文件夹,里边是c++层的代码。
2、进入到frameworks的工程目录下,打开对应的工程,我们用VS打开
3、在VS工程中我们写自己的类,这个类就是你要导出给Lua层用的接口,实际的需求可能是你一直在c++层写代码,某一部分的功能需要在Lua层来实现,这个时候有一些类需要导出给Lua使用,这里我们只是模拟一下,我们在Classes里写一个简单的TestLua类好了。
#ifndef __Test11__TestLua__ #define __Test11__TestLua__ #include "cocos2d.h" USING_NS_CC; class TestLua : public Ref { public: bool init(){return true;}; CREATE_FUNC(TestLua); int show(int); }; #endif /* defined(__Test11__TestLua__) */TestLua.h
#include "TestLua.h" int TestLua::show(int arg) { log("xiaota show %d",arg); return arg+100; }TestLua.cpp
文件结构在VS像下图这个样子
4、现在需要做的就是导出这个类的接口给Lua使用了。现在进入工程的frameworks/cocos2d-x/tools/bindings-generator目录下,仔细阅读README.md文档,将必须配置的工具和环境变量配置好。不用仔细阅读了,一堆英文看着也很烦呀,主要就是下图:
这里主要就是python2.7,py-yaml和cheetah这三样,libclang是神马玩意我也没管,不装也没事。因为要用到python里的easy-install 工具,此工具不明白怎么装怎么配置的同学可省事的安装python2.7.9或2.7.10,就自带了easy-install工具,还帮你把路径等环境变量配置好了,好了在console命令行运行 easy-install py-yaml和 easy-install cheetah吧,这样就差不多了
然后进入tolua目录,原目录下只有genbindings.py,我把这个文件复制了一份命名为genbindings2.py,然后复制了一个cocos2dx.ini文件,重新命名为xiaota.ini。genbindings.py文件是一个Python脚本,这个脚本在执行的过程中会读取.ini的配置文件,然后根据这些个配置文件生成我们需要的桥接类。
现在我们就来修改一下这两个重要的文件,网上有不少的童鞋没有成功的关键大多数是因为这俩个文件修改的不当所导致的,所以这一步至关重要!如下图所示,output_dir是将生成的桥接类放到哪个文件夹下,我这里放置的地方和引擎将桥接类放置的地方是相同的,cmd_args是在脚本执行的过程中读取的配置文件,我的配置文件是xiaota.ini,所以第一个参数就是xiaota.ini,其中你看到的lua_xiaota_auto这个东西就是最后生成的桥接类的名字。
genbindings2.py修改:
xiaota.ini修改
5、接下来就需要使用Python脚本来生成我们的桥接类了,网上不少的同学最后的结果都是失败,为了排除错误,你可以先运行genbindings.py,看看是否成功,如果不成功那么就是你环境配置的有问题,如果成功再运行自己的genbindings2.py文件,不成功的话80%的错误都是ini配置文件没有配置正确。
在genbindings.py所在目录下打开命令行下(空白处shift+右击,会出现在"此处打开命令窗口菜单")执行 python genbindings2.py,成功如下图:
编译成功,我们可以到刚才生成桥接类的文件夹下看一下这个文件。
根据刚才的配置文件设置,文件在frameworks\cocos2d-x\cocos\scripting\lua-bindings\auto
在那个api目录里还有个TestLua.lua文件,就是全是注释的api声明,那个不用管它。
6、下面我们就使用这个桥接类来将我们的类注册到Lua环境中。打开AppDelegate.cpp文件,包含一下桥接类lua_xiaota_auto.hpp,然后在applicationDidFinishLaunching函数中写如下的代码。
其中的register_all_xiaota就是用来注册类的,它是桥接类中的一个比较重要的函数。
7、为了编译这个桥接类,我们需要将这个新生成的类加入到工程中,此步至关重要。我在这一步耗费了两个晚上的时间来没日没夜的修改,调试。这一步最后试出来跟原文作者不一样,原来两个生成的lua桥接类lua_xiaota_auto.hpp,lua_xiaota_auto.cpp是在cocos\scripting\lua-bindings\auto目录里的,原文为了编译它是把libcocos2d库整个又重编一遍,我照它做了结果又是少Lua51.h又是少lua.c等一堆lua依赖库,又加一堆附加目录死活整不好,而且lua_xiaota_auto.cpp里有一句#include "TestLua.h",我最后把这个lua_xiaota_auto.hpp,lua_xiaota_auto.cpp复制一份与TestLua.h都放到Classes目录下,OK居然编译成功了
8,拿什么编译,我们还是用Cocos Code IDE来编译吧,不要用VS了,成功率还高点
经过这些步骤以后基本就算成功了,跑程序的时候我们使用这个最新的runtime,大家需要明确的一点是当我们改变c++层的代码的时候就需要重新build一下runtime,说白了就是重新编译一下c++的文件,让Lua脚本运行在一个新的环境下。
9. Cocos Code IDE Run菜单 -》edit configuration...来设一下新的Simulator10、最后一步,打开工程的main.lua,在工程中使用导出来的接口,最终来验证一下是否成功。
local function main() collectgarbage("collect") -- avoid memory leak collectgarbage("setpause",100) collectgarbage("setstepmul",5000) local val = tt.TestLua:create():show(10) print(val) end
一句话,不经历风雨,怎么见彩虹,经过了这么多步折腾,终于见到了成果,大家好好欣赏下吧,原来不用VS用Cocos Code IDE也是能绑定C++类的
大家找不到Cocos Code IDE 2.0的我分享下http://pan.baidu.com/s/1geyU3B1,此版本最好的地方是可以调试了不像1.0老是出问题,此版有一个重大BUG是代码编辑部分会突然变成插入状态不能编辑了 这时键盘按下 S键即可解决!