zoukankan      html  css  js  c++  java
  • 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支持多个返回值的函数)

  • 相关阅读:
    PNG文件格式具体解释
    opencv2对读书笔记——使用均值漂移算法查找物体
    Jackson的Json转换
    Java实现 蓝桥杯VIP 算法训练 装箱问题
    Java实现 蓝桥杯VIP 算法训练 装箱问题
    Java实现 蓝桥杯VIP 算法训练 单词接龙
    Java实现 蓝桥杯VIP 算法训练 单词接龙
    Java实现 蓝桥杯VIP 算法训练 方格取数
    Java实现 蓝桥杯VIP 算法训练 方格取数
    Java实现 蓝桥杯VIP 算法训练 单词接龙
  • 原文地址:https://www.cnblogs.com/sevenyuan/p/3707088.html
Copyright © 2011-2022 走看看