【cocos2d-x】使用 tolua 导出自定义 c++ 类

「爱情、让人受尽委屈。」 2022-06-07 06:51 214阅读 0赞

开始之前

首先来看一下 cocos2d-x3.x 的源码目录结构(这篇文章以 3.10 为例,只列出重要的几个目录和文件)

  1. |-cocos2d-x3.10
  2. |-tools
  3. |-tolua
  4. |-genbindings.py
  5. |-cocos2dx.ini
  6. |-cocos2dx_ui.ini
  7. |-...
  8. |-README.mdown
  9. |-bindings-generator
  10. |-libclang
  11. |-libclang.dll
  12. |-libclang.so
  13. |-libclang.dylib
  14. |-clang
  15. |-cindex.py
  16. |-generator.py
  17. |-cocos
  18. |-2d
  19. |-...
  20. |scripting
  21. |-js-bindings
  22. |-lua-bindings
  23. |-auto
  24. |-api
  25. |-Action.lua\
  26. |-...
  27. |-lua_cocos2dx_auto.hpp
  28. |-lua_cocos2dx_auto.cpp
  29. |-lua_cocos2dx_ui_auto.hpp
  30. |-lua_cocos2dx_ui_auto.cpp
  31. |-...

主要列出了 tools 和 cocos 这两个文件夹下的主要内容,cocos 目录是 cocos2d-x 引擎的源码(C++),其中 lua-bindings 目录下是导出的脚本语言,包括 js 和 lua;在 lua-bindings 下有个 auto 文件夹,这就是 tolua 生成文件存放的地方。tools 目录下是 cocos2d-x 非常实用的一些工具,包括创建项目、编译项目、运行项目的控制台命令等,这里我们要看的是 tolua 和 bindings-generator 这两个文件夹;tolua 目录毫无疑问就是这篇文章的主角,接下来我们要做的工作就是在这个目录下完成的;binding-generator 目录下是一些 tolua 会用到的文件,其实我们不用理会,这里列出来只是为了告诉大家 tolua 会用到这几个文件。

准备工作

在开始之前我们需要做一个准备工作,就是配置环境。cocos 环境和 android 环境就不用讲了,还需要配置的是 python 环境,因为 cocos2d-x 的 tolua 是使用 python 脚本来执行的。这个工作看 tools/tolua/README.mdown 这个文件就行了,下面翻译一下

  • 首先,安装 ndk 并配置环境变量 NDK_ROOT
  • 然后,下载安装 python2.7,注意必须安装 32 位版本,下载地址
    python2.7.3
  • 配置 python 环境变量 PYTHON_BIN
  • 下载安装 python 库 pyyaml,下载地址
    pyyaml,pyyaml 安装的时候会读取 python 安装路径并将结果安装在 %PYTHON_BIN%\Lib\site-packages 目录下
  • 下载 python 库 pyCheetah,下载地址
    pyCheetah,下载之后解压到 %PYTHON_BIN%\Lib\site-packages 目录下即可

使用 tolua

首先,跟写普通 c++ 程序一样,我们先写一个要导出的 c++ 类 MyClass

头文件

  1. //MyClass.h
  2. class MyClass
  3. {
  4. public:
  5. MyClass(int a, int b);
  6. ~MyClass();
  7. int excute();
  8. private:
  9. int a;
  10. int b;
  11. };

源文件

  1. //MyClass.cpp
  2. #include "MyClass.h"
  3. MyClass::MyClass(int a, int b)
  4. {
  5. this->a = a;
  6. this->b = b;
  7. }
  8. MyClass::~MyClass()
  9. {
  10. }
  11. int MyClass::excute()
  12. {
  13. return a + b;
  14. }

接下来就可以准备导出这个类了,使用的是 tools/tolua/genbindings.py,这个 python 脚本可以导出 cocos2d-x 中的所有类,我们可以修改这个脚本,添加我们自定义的类,也可以模仿这个脚本另外写一个脚本,然后执行我们自己写的这个脚本。为了防止破坏源代码,我们使用第二种,把 genbindings.py 复制一份,命名为 genbindings_myclass.py,然后修改下面两处地方

  1. # genbindings_myclass.py
  2. tolua_root = '%s/tools/tolua' % project_root
  3. output_dir = '%s/tests/custom/auto' % project_root
  4. cmd_args = {
  5. 'myclass.ini' : ('myclass', 'lua_myclass_auto')}

tolua_root 是 tolua 的根目录,不用修改;output_dir 是 tolua 生成的文件存放路径,原来的路径是 cocos/scripting/lua-bindings/auto,为了不和 cocos2d-x 的源代码混在一起,我们另外 cocos2d-x3.10/tests 目录新创建文件夹 custom/auto,把我们前面创建的 MyClass 类也放进去(这个路径随便放都行,只要配置文件中的路径不要写错就行)

  1. |-cocos2d-x3.10
  2. |-tests
  3. |-custom
  4. |-MyClass.h
  5. |-MyClass.cpp
  6. |-auto

cmd_args 是一个 table,指定我们要导出的 c++ 类,key 是一个 ini 配置文件,value 指定源文件名和导出文件名。cmd_args 可以指定多个 ini 配置文件,一个配置文件配置一个类或多个类;这里我们需要一个 myclass.ini,这个文件从哪来呢,直接在 tools/tolua 目录复制一个即可,复制之后修改下面内容

  1. # 源文件名,与上面 cmd_args 配置的一致
  2. [myclass]
  3. prefix = myclass
  4. # 导出的类所在命名空间,在 lua 层使用时需要用到,不写也行,表示在全局空间
  5. target_namespace = cc
  6. # 要导出的 c++ 类头文件路径
  7. headers = %(cocosdir)s/tests/custom/MyClass.h
  8. # 要导出的类名
  9. classes = MyClass
  10. skip =
  11. abstract_classes =

总结一下就是创建了 genbindings_myclass.py 和 myclass.ini 这两个文件,接下来在 tools/tolua 文件夹下打开命令行,输入

  1. python genbindings_myclass.py

如果没错误,将在 tests/custom/auto 目录生成相应的文件

  1. |-cocos2d-x3.10
  2. |-tests
  3. |-custom
  4. |-MyClass.h
  5. |-MyClass.cpp
  6. |-auto
  7. |-lua_myclass_auto.hpp
  8. |-lua_myclass_auto.cpp
  9. |-api
  10. |-MyClass.lua
  11. |-lua_myclass_auto.lua

如果报错,检查一下 genbindings_myclass.py 和 myclass.ini 有没有写错,特别是源文件路径 headers 和 目标文件 output_dir。还有就是 python,pyyaml 和 pyCheetah 是不是全装的 32 位,还有 python 环境变量是否配置对;当然 MyClass.h 和 MyClass.cpp 肯定也不能有错误。

测试

新建一个 lua 项目,把 MyClass.h,MyClass.cpp,lua_myclass_auto.hpp 和 lua_myclass_auto.cpp 这四个文件拷到项目中。然后打开 AppDelegate.cpp,添加下面内容

  1. #include "lua_myclass_auto.hpp"
  2. //...
  3. bool AppDelegate::applicationDidFinishLaunching()
  4. {
  5. //...
  6. //register custom function
  7. #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
  8. register_all_myclass(stack->getLuaState());
  9. #endif
  10. //...
  11. }

register_all_myclass 在 lua_myclass_auto.hpp 中声明,所以要引入这个头文件,在 lua_myclass_auto.cpp 中实现,我们可以看看这个函数

  1. TOLUA_API int register_all_myclass(lua_State* tolua_S)
  2. {
  3. tolua_open(tolua_S);
  4. tolua_module(tolua_S,"cc",0);
  5. tolua_beginmodule(tolua_S,"cc");
  6. lua_register_myclass_MyClass(tolua_S);
  7. tolua_endmodule(tolua_S);
  8. return 1;
  9. }

总的来说就是打开 tolua,把 c++ 层的函数注册到 lua 环境中,之后就可以在 lua 中直接使用这些函数了。具体的可以看我这篇文章
tolua 用法

接下来打开 src/app/views/MainScene.lua,开始测试我们的例子

  1. local MainScene = class("MainScene", cc.load("mvc").ViewBase)
  2. function MainScene:onCreate()
  3. local test = cc.MyClass:new(10, 20)
  4. local num = test:excute()
  5. local str = "Hello World" .. num
  6. cc.Label:createWithSystemFont(str, "Arial", 40)
  7. :move(display.cx, display.cy)
  8. :addTo(self)
  9. end
  10. return MainScene

这里我们创建 MyClass 的一个实例,然后调用其 excute 方法;注意我们前面导出的时候定义其命名空间为 cc,所以这里要写 cc.MyClass,否则会报错。这种 tolua 导出方式是针对 android 和 ios 的,所以在 pc 下是不行的,看一下 lua_myclass_auto.hpp 的源码就知道了

  1. #include "base/ccConfig.h"
  2. #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
  3. #ifndef __myclass_h__
  4. #define __myclass_h__
  5. #ifdef __cplusplus
  6. extern "C" {
  7. #endif
  8. #include "tolua++.h"
  9. #ifdef __cplusplus
  10. }
  11. #endif
  12. int register_all_myclass(lua_State* tolua_S);
  13. #endif // __myclass_h__
  14. #endif //#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS)

接下来就是见证成果的时候了,打包安卓 apk,然后安装运行,看到下面结果就表示大功告成了

tolua 应用

发表评论

表情:
评论列表 (有 0 条评论,214人围观)

还没有评论,来说两句吧...

相关阅读