重新回头看Luabinding

重新回头看Luabinding, Windows平台

  1. 需要的环境
  1. 自定义C++类'MyClass',我放在了runtime-src\Classes目录下面。

  2. 修改ini文件

一般直接在 **\frameworks\cocos2d-x\tools\tolua目录下操作。复制一份cocos2dx_ui.ini,重命名my_class.ini, 然后进行修改,下面是我修改后的:

[my_class]
# the prefix to be added to the generated functions. You might or might not use this in your own
# templates
prefix = my_class

# create a target namespace (in javascript, this would create some code like the equiv. to `ns = ns || {}`)
# all classes will be embedded in that namespace
target_namespace = zwf

# the native namespace in which this module locates, this parameter is used for avoid conflict of the same class name in different modules, as "cocos2d::Label" <-> "cocos2d::ui::Label".
cpp_namespace = 

android_headers = -I%(androidndkdir)s/platforms/android-14/arch-arm/usr/include -I%(androidndkdir)s/sources/cxx-stl/gnu-libstdc++/4.7/libs/armeabi-v7a/include -I%(androidndkdir)s/sources/cxx-stl/gnu-libstdc++/4.7/include -I%(androidndkdir)s/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi-v7a/include -I%(androidndkdir)s/sources/cxx-stl/gnu-libstdc++/4.8/include
android_flags = -D_SIZE_T_DEFINED_ 

clang_headers = -I%(clangllvmdir)s/lib/clang/%(clang_version)s/include 
clang_flags = -nostdinc -x c++ -std=c++11 -U __SSE__

cocos_headers = -I%(cocosdir)s/cocos -I%(cocosdir)s/cocos/editor-support -I%(cocosdir)s/cocos/platform/android

cocos_flags = -DANDROID

cxxgenerator_headers = 

# extra arguments for clang
extra_arguments = %(android_headers)s %(clang_headers)s %(cxxgenerator_headers)s %(cocos_headers)s %(android_flags)s %(clang_flags)s %(cocos_flags)s %(extra_flags)s 

# what headers to parse
headers = %(cocosdir)s/../runtime-src/Classes/MyClass.h

# what classes to produce code for. You can use regular expressions here. When testing the regular
# expression, it will be enclosed in "^$", like this: "^Menu*$".
classes = MyClass

# what should we skip? in the format ClassName::[function function]
# ClassName is a regular expression, but will be used like this: "^ClassName$" functions are also
# regular expressions, they will not be surrounded by "^$". If you want to skip a whole class, just
# add a single "*" as functions. See bellow for several examples. A special class name is "*", which
# will apply to all class names. This is a convenience wildcard to be able to skip similar named
# functions from all classes.

skip = 

rename_functions = 

rename_classes =

# for all class names, should we remove something when registering in the target VM?
remove_prefix = 

# classes for which there will be no "parent" lookup
classes_have_no_parents = Helper

# base classes which will be skipped when their sub-classes found them.
base_classes_to_skip =

# classes that create no constructor
# Set is special and we will use a hand-written constructor
abstract_classes = Helper AbstractCheckButton

# Determining whether to use script object(js object) to control the lifecycle of native(cpp) object or the other way around. Supported values are 'yes' or 'no'.
script_control_cpp = no

其中headers、classes、cpp_namespace是必须修改的。一般自定义的都不一样。
target_namespace标示的是到处的lua模块的命名空间,看个人喜好修改。
prefix这个是防止重命名的,一般都改成自定义的类应该就没问题了。
skip 不想导出的类级函数, 用于处理一些和lua不兼容的c++参数, 比如 std::function, std::pair 等, 这些参数没法通过栈空间传递给lua, 因此也就没办法导出给lua使用, 需要排除掉.

  1. 执行脚本genbindings.py,生成绑定文件。
    执行脚本之前,先修改脚本的配置,只生成我们自定义类的绑定文件就行,
cmd_args = {
            'my_class.ini' : ('my_class', 'lua_myclass_auto'), \
            }

然后在**\frameworks\cocos2d-x\tools\tolua目录下运行脚本,等待生成就可以了。(尽量在这个目录下执行脚本,在其他目录有可能失败)

5.导入工程中使用。把新生成的lua_myclass_auto.hpp和lua_myclass_auto.cpp拷贝到runtime-src\Classes目录下,导入工程,然后注册一下就可以使用了,注册方法:

static int register_all_packages(lua_State*L)
{
    register_all_my_class(L);//这个是新加的注册方法
    return 0; //flag for packages manager
}

6.lua中调用

    local myClass = zwf.MyClass:new("1111") --注意构造函数绑定的时候暴露到lua中的接口
    myClass:printInfo()

到这里基本的binding流程就完成了。

需要注意的是自动binding并不支持std::function的回调,所以需要手动binding,贴一下我的C++代码和binding代码:
C++:

#pragma once
#include<functional>  //这个是std::function的头文件
#include<iostream>
class MyClass
{
    //定义一个函数类型
    typedef std::function<void(const char* string)> myCallBack;

public:
    MyClass(std::string name);
    ~MyClass();
    const std::string & getName();
    void setName(std::string name);
    void printInfo();

    //std::function作为参数传入
    void setCallBack(const myCallBack& callBack);
private:
    std::string _name;
    myCallBack _callBack;
};

binding代码:

int lua_my_class_MyClass_setCallBack(lua_State* tolua_S)
{
    int argc = 0;
    MyClass* cobj = nullptr;
    bool ok  = true;

#if COCOS2D_DEBUG >= 1
    tolua_Error tolua_err;
#endif


#if COCOS2D_DEBUG >= 1
    if (!tolua_isusertype(tolua_S,1,"MyClass",0,&tolua_err)) goto tolua_lerror;
#endif
    //获取对象
    cobj = (MyClass*)tolua_tousertype(tolua_S,1,0);

#if COCOS2D_DEBUG >= 1
    if (!cobj) 
    {
        tolua_error(tolua_S,"invalid 'cobj' in function 'lua_my_class_MyClass_setCallBack'", nullptr);
        return 0;
    }
#endif
    argc = lua_gettop(tolua_S)-1;
    if (argc == 1) 
    {
        std::function<void (const char *)> arg0;
        //获取参数
        LUA_FUNCTION handler = (toluafix_ref_function(tolua_S, 2, 0));

        //调用成员函数
        cobj->setCallBack([=](const char* str) {
            LuaStack* stack = LuaEngine::getInstance()->getLuaStack();
            stack->pushString(str);
            stack->executeFunctionByHandler(handler, 1);
            stack->clean();
        });
        lua_settop(tolua_S, 1);
        return 1;
    }
    luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d \n", "MyClass:setCallBack",argc, 1);
    return 0;
#if COCOS2D_DEBUG >= 1
    tolua_lerror:
    tolua_error(tolua_S,"#ferror in function 'lua_my_class_MyClass_setCallBack'.",&tolua_err);
#endif
    return 0;
}

绑定流程主要也是这三步:

  • 获取c++对象
  • 获取参数, 校验参数类型
  • 调用成员函数

调用成员函数的时候,用到了Lambda表达式。这个不太熟,需要恶补一下。先挖个坑
然后就是Lua跟C++调用的时候内存原理,也需要深入了解。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,509评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,806评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,875评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,441评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,488评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,365评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,190评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,062评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,500评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,706评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,834评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,559评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,167评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,779评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,912评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,958评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,779评论 2 354

推荐阅读更多精彩内容