• cocos2d-x 使用Lua


    转自:http://www.benmutou.com/blog/archives/49

    1. Lua的堆栈和全局表

    我们来简单解释一下Lua的堆栈和全局表,堆栈大家应该会比较熟悉,它主要是用来让C++Lua通信的,是的,它们并不认识对方,只能通过堆栈来沟通,就像写信一样。

    Lua的全局表又是什么呢?可以想象成是一个map哈希表结构,比如Lua有一个变量:

    name = “hello”

    那么,全局表就存放了”name”和”hello”的对应关系,Lua可以通过name在全局表中查找到hello。应该是这样的~

    2. LuaC++的第一次通信

    -- hello.lua 文件
    myName = "beauty girl"

    然后,C++想知道Lua叫什么名字,所以,它们必须要通信了。来看看通信流程:

    请注意红色数字,代表通信顺序:

    1) C++想获取LuamyName字符串的值,所以它把myName放到Lua堆栈(栈顶),以便Lua能看到

    2) Lua从堆栈(栈顶)中获取myName,此时栈顶再次变为空

    3) Lua拿着这个myNameLua全局表查找myName对应的字符串

    4) 全局表返回一个字符串”beauty girl”

    5) Lua把取得的“beauty girl”字符串放到堆栈(栈顶)

    6) C++可以从Lua堆栈中取得“beauty girl”,也就是这位美丽的Lua小姐的名字了~

    3. 引入头文件

    我们来看看要在C++中使用Lua,需要些什么东西

    /* 
       文件名:    HelloLua.h 
       描 述:    Lua Demo
       创建人:    笨木头 (CSDN博客:http://blog.csdn.net/musicvs) 
    
       创建日期:   2012.12.24 
    */  
    
    #ifndef __HELLO_LUA_H_
    #define __HELLO_LUA_H_
    
    #include "cocos2d.h"
    
    extern "C" {
    #include <lua.h>
    #include <lualib.h>
    #include <lauxlib.h>
    };
    
    using namespace cocos2d;
    
    class HelloLua : public CCLayer {
    public:
        CREATE_FUNC(HelloLua);
        virtual bool init();
    
        static CCScene* scene();
    };
    
    #endif

    4. 开始使用

    来看看我们的cpp文件,我们要开始使用Lua~

    #include "HelloLua.h"
    
    CCScene* HelloLua::scene() {
        CCScene* scene = CCScene::create();
        CCLayer* layer = HelloLua::create();
        scene->addChild(layer);
    
        return scene;
    }
    
    bool HelloLua::init() {
        lua_State* pL = lua_open();
        luaopen_base(pL);
        luaopen_math(pL);
        luaopen_string(pL);
    
        /* 1.执行Lua脚本,返回0代表成功 */
        /* 2.重置栈顶索引 */
        /* 3.判断栈顶的值的类型是否为String, 返回非0值代表成功 */
      /* 4.获取栈顶的值 */
      
        lua_close(pL);
        return true;
    }

    5. 执行Lua脚本

    现在我们来一步步完善我们的代码,执行Lua脚本很简单,看看:

    bool HelloLua::init() {
        lua_State* pL = lua_open();
        luaopen_base(pL);
        luaopen_math(pL);
        luaopen_string(pL);
    
        /* 1.执行Lua脚本,返回0代表成功 */
        int err = luaL_dofile(pL, "helloLua.lua");
        CCLOG("open : %d", err);
    
        /* 2.重置栈顶索引 */
        lua_settop(pL, 0);
        lua_getglobal(pL, "myName");
    
        /* 3.判断栈顶的值的类型是否为String, 返回非0值代表成功 */
      /* 4.获取栈顶的值 */
      
        lua_close(pL);
        return true;
    }

    6. 重置栈顶索引, 将全局变量放到堆栈中

    lua_settop(pL, 0);是为了确认让栈顶的索引置为0,因为我们操作栈的时候是根据索引来操作的。置0之后,我们入栈的第一个元素的索引就是1

    那,lua_getglobal(pL, “myName”);又是什么呢?咋一看好像是从lua中取得myName这个全局变量的值,但并不是这样的,虽然最终也是这样。

    我们之前说过了,LuaC++是不能直接通信的,要通过堆栈来通信。

    因此,lua_getglobal(pL, “myName”);只是把myName放到了栈中,然后lua就会通过myName去全局表寻找,找到myName对应的字符串“beauty girl”,再放到栈中。

    7. C++取得字符串

    我们来看看完整的代码:

    bool HelloLua::init() {
        lua_State* pL = lua_open();
        luaopen_base(pL);
        luaopen_math(pL);
        luaopen_string(pL);
    
        /* 1.执行Lua脚本,返回0代表成功 */
        int err = luaL_dofile(pL, "helloLua.lua");
        CCLOG("open : %d", err);
    
        /* 2.重置栈顶索引 */
        lua_settop(pL, 0);
        lua_getglobal(pL, "myName");
    
        /* 3.判断栈顶的值的类型是否为String, 返回非0值代表成功 */
        int isstr = lua_isstring(pL, 1);
        CCLOG("isstr = %d", isstr);
    
        /* 4.获取栈顶的值 */
        const char* str = lua_tostring(pL, 1);
        CCLOG("getStr = %s", str);
    
        lua_close(pL);
        return true;
    }

    lua_getglobal已经完成了很多工作了,现在堆栈上就放着“beauty girl”字符串,我们只要去取就可以了。

    获取堆栈的值有很多种方法,分别对应不同的变量类型:

    lua_toboolean

    lua_toNumber

    lua_tocfunction

    lua_tostring

    我就不全部举例了,现在我们要用lua_tostring来获取栈顶的值。

    最后,在AppDelegate.cpp中把默认启动场景设为我们的HelloLua场景,用调试模式运行项目,将看到以下日志:

    open : 0

    isstr = 1

    getStr = beauty girl

    堆栈索引

     

    1. 正数索引,栈底是1

    2. 负数索引,栈顶是-1

    8. C++调用Lua函数

    -- helloLua.lua文件
    myName = "beauty girl"
    
    helloTable = {name = "mutou", IQ = 125}
    
    function helloAdd(num1, num2)
        return (num1 + num2)
    end;

    C++调用helloAdd函数

    /* C++调用lua的函数 */
    void HelloLua::demo3() {
        lua_State* pL = lua_open();
        luaopen_base(pL);
    
        /* 执行脚本 */
        luaL_dofile(pL, "helloLua.lua");
    
        /* 把helloAdd函数对象放到栈中 */
        lua_getglobal(pL, "helloAdd");
    
        /* 把函数所需要的参数入栈 */
        lua_pushnumber(pL, 10);
        lua_pushnumber(pL, 5);
    
        /* 
            执行函数,第一个参数表示函数的参数个数,第二个参数表示函数返回值个数 ,
            Lua会先去堆栈取出参数,然后再取出函数对象,开始执行函数
        */
        lua_call(pL, 2, 1);
    
        int iResult = lua_tonumber(pL, -1);
        CCLOG("iResult = %d", iResult);
    }

    简单说明一下步骤:

    1) 将helloAdd函数放到栈中:lua_getglobal(pL, “helloAdd”) 。(旁白:看吧,我就知道~!)

    2) helloAdd2个参数,我们要把参数传递给lua,所以2个参数都要放到栈里。

    3) 第2和第3步已经把函数所需要的数据都放到栈里了,接下来只要告诉lua去栈里取数据,执行函数~

    9. Lua调用C++函数

    创建一个c++函数先:

    public:
      static int getNumber(int num);
      
      
    int HelloLua::getNumber( int num ) {
        CCLOG("getNumber num = %d", num);
        return num + 1;
    }

    现在,我们想在Lua中调用这个函数,得多写一个函数。

    public:
    static int cpp_GetNumber(lua_State* pL);
    
    
    int HelloLua::cpp_GetNumber( lua_State* pL ) {
        /* 从栈顶中取一个值 */
        int num = (int)lua_tonumber(pL, 1);
    
        /* 调用getNumber函数,将返回值入栈 */
        lua_pushnumber(pL, getNumber(num));
    
        /* 返回值个数,getNumber只有一个返回值,所以返回1 */
        return 1;
    }

    这是怎么回事呢?我们很清楚,LuaC++只能通过堆栈通信,所以Lua是不可能直接调用getNumber函数的,所以我们建立一个cpp_GetNumber函数作为中介。

    cpp_GetNumber函数有一个lua_State* pL参数,有了这个参数,c++就能从Lua的堆栈中取值了

    1) 首先,Lua脚本里会调用cpp_GetNumber函数。

    2) 当cpp_GetNumber被调用时,一切又回到C++Lua的操作了,栈顶里会存放函数所需要的参数,取出来用就可以的。

    3) Lua调用cpp_GetNumber之后,需要一个结果,当然,这个结果同样只能存放在栈里,所以理所当然地要把getNumber的结果入栈。

    4) 最后,cpp_GetNumber return了一个值,这个值不是函数的执行结果,而是getNumber需要返回值的个数(Lua支持多个返回值的函数)

  • 相关阅读:
    设计模式01之 简单工厂模式(创建模式)
    UML系列05之 基本流程图
    UML系列04之 UML时序图
    UML系列03之 UML类图(二)
    UML系列02之 UML类图(一)
    LaTex in Markdown
    Ubuntu18.04 下的Gif录制工具
    Python3 与 C# 扩展之~基础衍生
    Python3 与 C# 扩展之~模块专栏
    Python3 与 C# 面向对象之~异常相关
  • 原文地址:https://www.cnblogs.com/sevenyuan/p/3707088.html
Copyright © 2020-2023  润新知