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

1. Lua的堆栈和全局表

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

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

name = “hello”

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

2. Lua和C++的第一次通信

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

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

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

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

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

3) Lua拿着这个myName去Lua全局表查找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, );
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这个全局变量的值,但并不是这样的,虽然最终也是这样。

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

因此,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, );
lua_getglobal(pL, "myName"); /* 3.判断栈顶的值的类型是否为String, 返回非0值代表成功 */
int isstr = lua_isstring(pL, );
CCLOG("isstr = %d", isstr); /* 4.获取栈顶的值 */
const char* str = lua_tostring(pL, );
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 = } 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, );
lua_pushnumber(pL, ); /*
执行函数,第一个参数表示函数的参数个数,第二个参数表示函数返回值个数 ,
Lua会先去堆栈取出参数,然后再取出函数对象,开始执行函数
*/
lua_call(pL, , ); int iResult = lua_tonumber(pL, -);
CCLOG("iResult = %d", iResult);
}

简单说明一下步骤:

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

2) helloAdd有2个参数,我们要把参数传递给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 + ;
}

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

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

这是怎么回事呢?我们很清楚,Lua和C++只能通过堆栈通信,所以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支持多个返回值的函数)

cocos2d-x 使用Lua的更多相关文章

  1. 使用cocos2d脚本生成lua绑定

    这几天要老大要求把DragonBones移到cocos2dx 3.0 里边,并且绑定lua使用接口.因为刚学lua,使用的引擎也刚从2.2改为3.0,各种不熟悉,折腾了好几天才弄完,有空了总结一下 这 ...

  2. cocos2d 3.3 lua 代码加密 luac

    1.0 cocos luacompile 使用方法 我用的普通的cocos2d lua,没用quick,quick好像能够对整个资源包含图像和音频都加密,打包成zip.我看了下luacompile 的 ...

  3. 采用cocos2d-x lua 制作数字滚动效果样例

    require "Cocos2d"require "Cocos2dConstants"local testscene = class("testsce ...

  4. 采用cocos2d-x lua 的listview 实现pageview的翻页效果之上下翻页效果

    --翻页滚动效果local function fnScrollViewScrolling( sender,eventType)    -- body    if eventType == 10 the ...

  5. cocos2dx-3.x 导出自定义类到 lua 过程详解

    转载请注明出处:http://www.cnblogs.com/Ray1024 一.简介 最近正在学习cocos2d中的lua游戏开发,因为lua开发的热更新特性,大家开发游戏好像都会优先选择lua作为 ...

  6. 在cocos code ide的基础上构建自己的lua开发调试环境

    对于一种语言,其所谓开发调试环境, 大体有以下两方面的内容: 1.开发, 即代码编写, 主要是代码提示.补齐, 更高级一点的如变量名颜色等. 2.调试, 主要是运行状态下断点.查看变量.堆栈等. 现在 ...

  7. 【转】cocos2d-x Lua

    Call custom c++ from Lua cocos2d-x lua binds c++ class, class functions ,enum and some global functi ...

  8. Cocos 2d-X Lua 游戏添加苹果内购(二) OC和Lua交互代码详解

    这是第二篇 Cocos 2d-X Lua 游戏添加苹果内购(一) 图文详解准备流程 这是前面的第一篇,详细的说明了怎样添加内购项目以及填写银行信息提交以及沙盒测试员的添加使用以及需要我们注意的东西,结 ...

  9. iOS应用动态部署方案

    iOS的动态部署能极大的节约成本.苹果的审核周期很长,有的时候,你可能不得不等待将近2个星期去上架你的新功能或者bug.所以动态部署是有价值的. 我这里讨论的情况不把纯web应用考虑在内,因为用户体验 ...

  10. Cocos2d-x移植安卓的笔记

    一.下载所需软件 Java SDK   http://www.oracle.com/technetwork/java/javase/downloads/index.html  Windows x64 ...

随机推荐

  1. nodejs学习--express篇

    express篇:http://www.runoob.com/nodejs/nodejs-express-framework.html Express 提供了内置的中间件 express.static ...

  2. python基础之使用os.system来执行系统命令

    今天我们来尝试使用python 的os.system来执行系统命令 可以使用如下方法: import osprint os.system('ping www.baidu.com') 输出的结果是:64 ...

  3. 基于CentOS与VmwareStation10搭建Oracle11G RAC 64集群环境:2.搭建环境-2.5. 配置网络

    2.5. 配置网络 2.5.1. 配置网络 Oracle Rac数据库涉及到公用网络和私有网络,因此要做网络划分和IP地址规划,下表列出了要安装的RAC数据库对应的IP地址.主机名以及网络连接类型: ...

  4. Hibernate查询出现java.lang.IllegalArgumentException异常解决方法

    Hibernate查询出现java.lang.IllegalArgumentException. 异常信息如下:java.lang.IllegalArgumentException        at ...

  5. 嵌入式 hi3518平台获取网关

    </pre><pre code_snippet_id="495447" snippet_file_name="blog_20141024_1_70650 ...

  6. 白盒测试之初识gtest工具

    因为公司最近对软件产品质量提高了要求,之前项目组中黑盒测试方法就越来越无法满足公司的要求.虽然作为研发,但是也要求对白盒测试有一个系统的了解(毕竟之前没有系统的接触过白盒测试). 单元测试工具有很多种 ...

  7. php sortable 动态排序

    php sortable 动态排序未分页版.php 预览图: <?php mysql_connect("localhost","root","r ...

  8. IOS平台设计规范

    一.UI的控件概述: 1.框架UI的元素分为4类: A:栏:状态栏目和导航栏的结合体; B:内容视图:应用显示的内容信息,包括相关的交互行为,例如滚屏.插入.删除等操作进行排序; C:控制元素:产品行 ...

  9. effective c++:dynamic_cast,避免返回handles指向对象内部

    关于dynamic_cast 假定我们有一个基类指针bp,我们在运行时需要把它转换成他的派生类指针,这个时候需要用到dynamic_cast. Derived *dp = dynamic_cast&l ...

  10. QQ群聊天记录文件分割

    嗯,如题 是个蛋疼物 目前QQ的聊天记录导出功能很让人郁闷 三种聊天记录格式的导出 1  TXT   没图 2  BAK  只能再导入QQ使用 3  MHT 有图有字,缺点是一旦聊天记录很多,文件体积 ...