• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Lua和C++交互

武飞扬头像
泡泡茶壶Wending
帮助1

Lua 解释器是用来执行的 lua代码的C程序。Lua 解释器是一个使用 Lua 标准库实现的独立的解释器,她是一个很小的应用(总共不超过 500 行的代码)。解释器负责程序和使用者的接口:从使用者那里获取文件或者字符串,并传给 Lua 标准库,Lua 标准库负责最终的代码运行。

Lua 可以作为程序库用来扩展应用的功能,也就是 Lua 可以作为扩展性语言的原因所在。同时,Lua 程序中可以注册有其他语言实现的函数,这些函数可能由 C 语言(或其他语言)实现,可以增加一些不容易由 Lua 实现的功能。这使得 Lua 是可扩展的。与上面两种观点(Lua 作为扩展性语言和可扩展的语言)对应的 C 和 Lua 中间有两种交互方式。
第一种,C 作为应用程序语言,Lua 作为一个库使用;
第二种,反过来,Lua 作为程序语言,C 作为库使用。这两种方式,C 语言都使用相同的 API 与 Lua 通信,因此 C 和Lua 交互这部分称为 C API。

C API 是一个 C 代码与 Lua 进行交互的函数集。他有以下部分组成:读写 Lua 全局变量的函数,获取和调用 Lua 函数的函数,运行 Lua 代码片断的函数,注册 C 函数然后可以在Lua 中调用被注册的函数,等等。

1.Lua调用C :
先一句话概括:根据规定好的函数类型(返回int,参数是Lua_State*(共享栈))编写C 函数,然后调用 lua_register把这些函数注册到Lua虚拟机中(函数名和C 函数指针做映射), 在LUA端就可以调用注册好的函数
当我们需要在Lua里面调用c/c 函数时,所有的函数都必须满足以下函数签名:
typedef int (*lua_CFunction) (lua_State *L);
换句话说,所有的函数必须接收一个lua_State作为参数,同时返回一个整数值。因为这个函数使用Lua栈作为参数,所以它可以从栈里面读取任意数量和任意类型的参数。而这个函数的返回值则表示函数返回时有多少返回值被压入Lua栈。(因为Lua的函数是可以返回多个值的)
C 和Lua通过共享内存(LUA栈)来通信,LUA API中很多操作LUA栈的接口,cocos使用luabinding.py脚本生成 桥接文件(文件内容是暴露给 LUA端C 函数), 然后需要调用lua_register接口,注册这些函数到 Lua虚拟机中 ,然后在LUA端就可以调用注册好的函数
  1.  
    static int averageFunc(lua_State *L)
  2.  
    {
  3.  
    int n = lua_gettop(L);//获取栈顶元素,表示参数数量
  4.  
    double sum = 0;
  5.  
    int i;
  6.  
    /* 循环求参数之和 */
  7.  
    for (i = 1; i <= n; i )
  8.  
    sum = lua_tonumber(L, i);
  9.  
    lua_pushnumber(L, sum / n); //压入平均值
  10.  
    lua_pushnumber(L, sum); //压入和
  11.  
    return 2; //返回两个结果
  12.  
    }
  13.  
    static int sayHelloFunc(lua_State* L)
  14.  
    {
  15.  
    printf("hello world!");
  16.  
    return 0;
  17.  
    }
  18.  
    static const struct luaL_Reg myLib[] =
  19.  
    {
  20.  
    {"average", averageFunc},
  21.  
    {"sayHello", sayHelloFunc},
  22.  
    {NULL, NULL} //数组中最后一对必须是{NULL, NULL},用来表示结束
  23.  
    }
  24.  
    int luaopen_mLualib(lua_State *L)
  25.  
    {
  26.  
    luaL_register(L, "ss", myLib);
  27.  
    return 1; // 把myLib表压入了栈中,所以就需要返回1
  28.  
    }
学新通

 
2.C 调用Lua: 使用lua_getglobal相关接口从lua栈中找到LUA全局变量,找到的是函数的话,把需要传入的参数依次压入栈即可,lua_pcall来执行函数,调用完成以后,会将返回值压入栈中。
cocos2dx中的实现:
一: lua 调用c
1.编写一个.ini文件 
路径为 TestLua\frameworks\cocos2d-x\tools\tolua , 随意复制一个ini 文件 改为自己需要的ini文件
如: testCn.ini
2. 修改genbindings.py脚本 添加需要调用的类
3.执行genbindings.py脚本。  会生成.hpp和.cpp 桥接 文件。
4. 将生成的桥接文件加入工程 
5.修改lua_module_register.cpp 在lua_module_register函数中 注册 新增的函数
6.Lua中的使用
7.因为创建之后,编译成apk时,需要找到对应的文件,需要在mk文件添加 不然编译的时候提示 " error: undefined reference to register_all_testCn" 未定义
1)jni/Android.mk文件添加   ../../Classes/TestCn.cpp \
二:C 调用lua
c 部分代码
>>>>>> 这里只调用不带参数全局方法(含返回值),需要多参数的查看参考文章即可
auto engine = LuaEngine::getInstance();
bool num = engine->executeGlobalFunction("myTest");
lua部分
>>>>>>>>>>>>>>>>>
在main函数增加 myTest 函数 即可
function myTest()
 print("mytest")
 return 100
end
值得注意的  坑
!!!!! 由于config.lua中限定了是否可以使用全局方法 CC_DISABLE_GLOBAL!!!!!!!!
CC_DISABLE_GLOBAL = false  设置为false才可以调用

例子讲解:

local spr = cc.Sprite:create()

cc是一张表(table),表(table)是lua里面唯一的数据结构,cc存于_G中,_G是lua里面的全局表,cc表中存了所有cocos绑定的常量和“类”。

Sprite也是个表(table),Sprite表是怎样跟c 代码关联起来的呢,这就要分析c 的绑定代码了。首先来看看Sprite表里面的内容

  1.  
    ["Sprite"] = {--table: 0x0032cce0
  2.  
    [".isclass"] = "true",
  3.  
    [".metatable"] = table: 0x0032c690
  4.  
    },

通过打印发现,Sprite表里面就一条数据key=[".isclass"] value=true,这个表明这个此table是cocos绑定的一个类型。看来秘密都在元表(metatable)里面。元表(metatable)在注册表(LUA_REGISTRYINDEX)里面,关于lua的全局表(_G)、注册表(Register)、元表(metatable),这里不再介绍了,不理解的需要先去学习一下。下面来打印一下Sprite的元表(metatable)里面的内容

  1.  
    ["cc.Sprite"] = {--table: 0x0032c690
  2.  
    ["getTextureRect"] = "function: 0x00b9b430",
  3.  
    ["getBatchNode"] = "function: 0x00b9afe8",
  4.  
    ["setTextureAtlas"] = "function: 0x00b9b770",
  5.  
    ["new"] = "function: 0x00b9b168",
  6.  
    ["setDisplayFrameWithAnimationName"] = "function: 0x00b9b750",
  7.  
    ["create"] = "function: 0x003284a8",
  8.  
    ["__lt"] = "function: 0x0032cbf0",
  9.  
    ["getTexture"] = "function: 0x00b9b2b8",
  10.  
    ["__sub"] = "function: 0x0032cc58",
  11.  
    ["initWithFile"] = "function: 0x00b9b450",
  12.  
    ["isTextureRectRotated"] = "function: 0x00b9b3e8",
  13.  
    ["removeAllChildrenWithCleanup"] = "function: 0x00b9b050",
  14.  
    ["setTextureRect"] = "function: 0x00b9b098",
  15.  
    ["setDirty"] = "function: 0x00b9b398",
  16.  
    ["getSpriteFrame"] = "function: 0x00b9b790",
  17.  
    ["__newindex"] = "function: 0x0032c710",
  18.  
    ["__eq"] = "function: 0x0032cc30",
  19.  
    ["setPolygonInfo"] = "function: 0x00328488",
  20.  
    ["initWithPolygon"] = "function: 0x00328440",
  21.  
    ["__le"] = "function: 0x0032cc10",
  22.  
    ["setFlippedX"] = "function: 0x00b9af60",
  23.  
    ["createWithSpriteFrame"] = "function: 0x00b9be50",
  24.  
    ["createWithSpriteFrameName"] = "function: 0x00b9be00",
  25.  
    ["tolua_ubox"] = "table: 0x002c86f0" , -- loop table,
  26.  
    ["createWithTexture"] = "function: 0x00b9b5c0",
  27.  
    ["setTexture"] = "function: 0x00b9b298",
  28.  
    ["setVertexRect"] = "function: 0x00b9b5a0",
  29.  
    ["isFlippedY"] = "function: 0x00b9b558",
  30.  
    ["isFlippedX"] = "function: 0x00b9b518",
  31.  
    ["getResourceType"] = "function: 0x00b9afa8",
  32.  
    ["setFlippedY"] = "function: 0x00b9b2f8",
  33.  
    ["setBlendFunc"] = "function: 0x003283f8",
  34.  
    ["__div"] = "function: 0x0032c6b8",
  35.  
    ["getTextureAtlas"] = "function: 0x00b9b490",
  36.  
    ["__index"] = "function: 0x0032c6f0",
  37.  
    ["setAtlasIndex"] = "function: 0x00b9b358",
  38.  
    ["getAtlasIndex"] = "function: 0x00b9b6b8",
  39.  
    ["isDirty"] = "function: 0x00b9b338",
  40.  
    ["getResourceName"] = "function: 0x00b9b7d8",
  41.  
    ["getOffsetPosition"] = "function: 0x00b9b030",
  42.  
    ["setBatchNode"] = "function: 0x00b9b6d8",
  43.  
    ["__gc"] = "function: 0x002c1a90",
  44.  
    ["__call"] = "function: 0x0032cc98",
  45.  
    ["__mul"] = "function: 0x0032cc78",
  46.  
    ["initWithSpriteFrame"] = "function: 0x00b9b4d8",
  47.  
    ["__add"] = "function: 0x0032c730",
  48.  
    ["initWithTexture"] = "function: 0x00b9afc8",
  49.  
    ["setSpriteFrame"] = "function: 0x00b9b1b0",
  50.  
    ["initWithSpriteFrameName"] = "function: 0x00b9b650",
  51.  
    ["isFrameDisplayed"] = "function: 0x00b9b698",
  52.  
    ["getBlendFunc"] = "function: 0x00b9b6f8",
  53.  
    [".metatable"] = table: 0x002ca9c8
  54.  
    }
学新通

cc.Sprite:create,在元表(metatable)的前半部分找到到了create方法,下面来看一看create方法里面的内容:

  1.  
    int lua_cocos2dx_Sprite_create(lua_State* tolua_S)
  2.  
    {
  3.  
    int argc = 0;
  4.  
    bool ok = true;
  5.  
    //lua_gettop获取栈顶正索引,也表示栈内的元素个数
  6.  
    argc = lua_gettop(tolua_S)-1;//获取栈顶下面的正索引
  7.  
    do{
  8.  
    if (argc == 1){//表示栈内有两个元素
  9.  
    std::string arg0;
  10.  
    ok &= luaval_to_std_string(tolua_S, 2,&arg0, "cc.Sprite:create");
  11.  
    if (!ok) { break; }
  12.  
    cocos2d::Sprite* ret = cocos2d::Sprite::create(arg0);
  13.  
    object_to_luaval<cocos2d::Sprite>(tolua_S, "cc.Sprite",(cocos2d::Sprite*)ret);
  14.  
    return 1;
  15.  
    }
  16.  
    } while (0);
  17.  
    luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d", "cc.Sprite:create",argc, 2);
  18.  
    return 0;
  19.  
    }
学新通

create方法当然也是一个c函数。lua_gettop()用来获取create函数参数数量,第一个参数是Sprite(table)自己,减1后是真正参数数量,所以create方法必须要用:号调用,元表中其它的方法也一样。函数先用luaval_to_std_string判断传入参数是否是std::string类型,其核心就是调用tolua_isstring函数来进行判定。然后就是调用cocos2d::Sprite::create()创建c 对象,然后调用object_to_luaval<>()函数把c 指针压入lua的栈中,理解这个函数是理解cocos lua的运作流程的关键。
 

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhggicbg
系列文章
更多 icon
同类精品
更多 icon
继续加载