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

开始之前

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

|-cocos2d-x3.10
    |-tools
        |-tolua
            |-genbindings.py
            |-cocos2dx.ini
            |-cocos2dx_ui.ini
            |-...
            |-README.mdown
        |-bindings-generator
            |-libclang
                |-libclang.dll
                |-libclang.so
                |-libclang.dylib
            |-clang
                |-cindex.py
            |-generator.py
    |-cocos
        |-2d
        |-...
        |scripting
            |-js-bindings
            |-lua-bindings
                |-auto
                    |-api
                        |-Action.lua\
                        |-...
                    |-lua_cocos2dx_auto.hpp
                    |-lua_cocos2dx_auto.cpp
                    |-lua_cocos2dx_ui_auto.hpp
                    |-lua_cocos2dx_ui_auto.cpp
                    |-...

主要列出了 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

头文件

//MyClass.h
class MyClass
{
public:
    MyClass(int a, int b);
    ~MyClass();
    int excute();

private:
    int a;
    int b;
};

源文件

//MyClass.cpp
#include "MyClass.h"

MyClass::MyClass(int a, int b)
{
    this->a = a;
    this->b = b;
}

MyClass::~MyClass()
{
}

int MyClass::excute()
{
    return a + b;
}

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

# genbindings_myclass.py
tolua_root = '%s/tools/tolua' % project_root
output_dir = '%s/tests/custom/auto' % project_root 
cmd_args = {'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 类也放进去(这个路径随便放都行,只要配置文件中的路径不要写错就行)

|-cocos2d-x3.10
    |-tests
        |-custom
            |-MyClass.h
            |-MyClass.cpp
            |-auto

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

# 源文件名,与上面 cmd_args 配置的一致
[myclass]
prefix = myclass

# 导出的类所在命名空间,在 lua 层使用时需要用到,不写也行,表示在全局空间
target_namespace = cc

# 要导出的 c++ 类头文件路径
headers = %(cocosdir)s/tests/custom/MyClass.h

# 要导出的类名
classes = MyClass

skip =
abstract_classes =

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

python genbindings_myclass.py

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

|-cocos2d-x3.10
    |-tests
        |-custom
            |-MyClass.h
            |-MyClass.cpp
            |-auto
                |-lua_myclass_auto.hpp
                |-lua_myclass_auto.cpp
                |-api
                    |-MyClass.lua
                    |-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,添加下面内容

#include "lua_myclass_auto.hpp"
//...

bool AppDelegate::applicationDidFinishLaunching()
{
    //...
    //register custom function
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    register_all_myclass(stack->getLuaState());
#endif
    //...
}

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

TOLUA_API int register_all_myclass(lua_State* tolua_S)
{
    tolua_open(tolua_S);

    tolua_module(tolua_S,"cc",0);
    tolua_beginmodule(tolua_S,"cc");

    lua_register_myclass_MyClass(tolua_S);

    tolua_endmodule(tolua_S);
    return 1;
}

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

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

local MainScene = class("MainScene", cc.load("mvc").ViewBase)

function MainScene:onCreate()
    local test = cc.MyClass:new(10, 20)
    local num = test:excute()
    local str = "Hello World" .. num
    cc.Label:createWithSystemFont(str, "Arial", 40)
    :move(display.cx, display.cy)
    :addTo(self)
end

return MainScene

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

#include "base/ccConfig.h"
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
#ifndef __myclass_h__
#define __myclass_h__

#ifdef __cplusplus
extern "C" {
#endif
#include "tolua++.h"
#ifdef __cplusplus
}
#endif

int register_all_myclass(lua_State* tolua_S);

#endif // __myclass_h__
#endif //#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS)

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

tolua 应用

猜你喜欢

转载自blog.csdn.net/xingxinmanong/article/details/78226825