Cocos2dx 3.x 使用 Python 进行 Lua 绑定,除了为每个类定制配置文件 *.ini
之外,还需要修改可执行脚本 generator.py
。
版本之痛,痛中之痛;环境之难,难中之难。
cocos2d-x3.x 与 2.x 很不一样,关于 Lua 绑定也不同。在 2.x 版本,引擎目录下有个 tolua++.exe
文件,通过包描述文件 *.tolua
,执行脚本 build.bat
来一键导出。而在 3.x 版本,描述文件换成了 *.ini
,然后编写 python 脚本 generator.py
,使用 python 来导出。
工程结构
首先来看一下 cocos2d-x3.x 的源码目录结构,
1 | |-cocos2d-x-3.x |
build
为工程目录,docs
帮助文档,tests
官方示例,templates
为创建项目时使用的模板,extensions
为源码的一些扩展,external
为外部库,主要是一些第三方的基础库,比如物理引擎、md5、json 等等。重点要介绍的是 tools
和 cocos
这两个文件夹。
cocos
目录是 cocos2d-x 引擎的 C++ 源码,其中cocos/scripting
为导出的脚本,包括 js 和 lua,分别放在cocos/scripting/lua-bindings
和cocos/scripting/js-bindings
目录下;cocos/scripting/lua-bindings/auto
为 tolua 生成文件存放的地方。tools
目录下是 cocos2d-x 非常实用的一些工具,包括创建项目、编译项目、运行项目的控制台命令等,这里我们要看的是tolua
和bindings-generator
这两个文件夹;tolua
下是包描述文件和可执行脚本genbindings.py
,binding-generator
目录下则是需要用到的一些库或脚本。
环境配置
在开始之前需要做一个准备工作,就是配置环境,主要配置的是 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 目录下即可。
Lua 绑定
首先,跟写普通 C++ 程序一样,我们先写一个要导出的 C++ 类 MyClass
。
1 | //MyClass.h |
接下来就可以准备导出这个类了,使用的是 tools/tolua/genbindings.py
以及每个类对应的 ini
文件,这个 python 脚本可以导出 cocos2d-x 中的所有类,我们可以修改这个脚本,添加我们自定义的类,也可以模仿这个脚本另外写一个脚本,然后执行我们自己写的这个脚本。为了防止破坏源代码,我们使用第二种,把 genbindings.py
复制一份,命名为 genbindings_myclass.py
,再把 cocos2dx.ini
复制一份,命名为 myclass.ini
。在引擎源码下创建一个 custom
目录,然后把 myclass.ini
和 C++ 源文件统一放在这个目录下,而 genbindings_myclass.py
则仍放在 tools/tolua
目录下,这样改动最小。
1 | |-cocos2d-x-3.x |
修改 genbindings_myclass.py
:
tolua_root
为包描述文件myclass.ini
的路径,即project_root/cocos/custom
;output_dir
为生成文件的路径,我们放在project_root/cocos/custom/auto
目录下;cmd_args
指定使用的配置文件以及导出的文件名,这是一个 table,可以指定多个 ini 配置文件,一个配置文件可以配置一个类或多个类,格式为"ini_file" : ("section", "output_file")
。这里我们只需要一个myclass.ini
,section
为myclass
,在myclass.ini
的第一行定义,导出的文件名为lua_myclass_auto
。
1 | # genbindings_myclass.py |
修改 myclass.ini
:
1 | # section,与上面 cmd_args 配置的一致 |
总结一下就是创建了 genbindings_myclass.py
和 myclass.ini
这两个文件,接下来在 tools/tolua
文件夹下打开命令行,输入 python genbindings_myclass.py
。 如果没错误,将在 tests/custom/auto
目录生成相应的文件。
1 | |-cocos2d-x-3.x |
如果报错,检查一下 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 |
|
register_all_myclass
在 lua_myclass_auto.hpp
中声明,所以要引入这个头文件,在 lua_myclass_auto.cpp
中实现,我们可以看看这个函数,
1 | TOLUA_API int register_all_myclass(lua_State* tolua_S) |
总的来说就是打开 tolua,把 c++ 层的函数注册到 lua 环境中,之后就可以在 lua 中直接使用这些函数了。具体的可以看我这篇文章tolua 用法。
接下来打开 src/app/views/MainScene.lua,开始测试我们的例子,
1 | local MainScene = class("MainScene", cc.load("mvc").ViewBase) |
这里我们创建 MyClass 的一个实例,然后调用其 excute 方法;注意我们前面导出的时候定义其命名空间为 cc,所以这里要写 cc.MyClass,否则会报错。接下来就是见证成果的时候了,编译运行项目,看到下面结果就表示大功告成了。
常见问题
1. NDK 版本不对
1 | ==== |
如果出现这个错误,是因为 NDK 工具链 llvm
匹配不上,最简单直接的办法就是换一个版本的 NDK,通常是使用了版本太高的 NDK 才会出现,比如我之前电脑上装了 r10 和 r20 两个版本,不知道什么时候环境变量设成了 NDK_ROOT = D:\Android\android-ndk-r20
,把它换成 NDK_ROOT = D:\Android\android-ndk-r10e
就行了。注意要删掉 tools/tolua/userconfi.ini
,然后重启终端再执行就可以了。
2. 类名、头文件路径写错
TranslationUnitLoadError: Error parsing translation unit.
如果报这个错,检查一下类名有没有写错,头文件路径是否正确。
<!https://www.jianshu.com/p/48a6fb7123ee>
3. 命名空间解析不了
Exception: The namespace (flash::FlashSpriteFrame) conversion wasn't set in 'ns_map' section of the conversions.yaml
其实这个报错信息很明显了,在 conversions.yaml
的 ns_map
section 中没找到这个命名空间的映射。也就是说如果定义了新的命名空间,不仅要在 ini 文件中定义 target_namespace
和 cpp_namespace
这两个字段,还要在 conversions.yaml
中定义这两个命名空间的映射关系,格式为 "cpp_namespace::": "target_namespace."
。
4. 脚本工作目录错误
No option 'cxxgeneratordir' in section: 'DEFAULT'
,报这个错主要是没有进入到脚本所在的目录去执行脚本,有些配置路径就不对了。
to be continue…