转自: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. js浮点数运算需要注意的问题

    最近在js运算浮点数时发现了一个问题.问题是这样的:js函数中处理两个浮点数的相加,为了防止出现0.1+0.2=0.30000000000000004的问题,两个数都先乘以10000后再相加,得到结果 ...

  2. Java Web 乱码

    1.mySql编码 2.jdbc编码 http://www.blogjava.net/NicholasEcho/archive/2008/11/03/238310.html ----- 1.HttpG ...

  3. SpringMvc+jquery easyui模块开发7步骤

    搞了一段java的开发,总结出模块开发经验: SpringMvc+jquery easyui模块开发7步骤:1) 数据表(table):                定义表结构并创建数据表t_use ...

  4. 腾讯内部举报信曝光: HR内斗混乱 玩弄求职者

    来自:http://www.guigu.org/news/guigushijie/2013102140759.html 腾讯CEO马化腾正在内部大搞思想整风运动,此时,猎云网独家获得数封来自腾讯内部的 ...

  5. 关于Cygwin的x-Server的自动运行以及相关脚本修改

    常常需要用到远端服务器的图形工具,如果在windows端没用xserver的话,很多程序无法运行.一个特殊的例子,emacs在没用xserver的时候,是直接在终端中打开的,如果不修改cygwin.b ...

  6. [转]Struts标签库详解

    本文转自:http://hi.baidu.com/xzkcz/blog/item/5cf9f91f01beb9f4e0fe0bd4.html   Struts提供了五个标签库,即:HTML.Bean. ...

  7. 说说Python 中的文件操作 和 目录操作

    我们知道,文件名.目录名和链接名都是用一个字符串作为其标识符的,但是给我们一个标识符,我们该如何确定它所指的到底是常规文件文件名.目录名还是链接名呢?这时,我们可以使用os.path模块提供的isfi ...

  8. DouNet学习_收发邮件

    一.收发邮件 --->第一步:发邮件首先要有发送者的邮箱地址和登录的密码才能发送 这些都写在APP里  不要写死 --->第二步:发邮件就要有网络,要添加net.Mail命名空间 要发送的 ...

  9. kali 更新源

    个人收集的kali 更新源: 修改更新源: vim /etc/apt/sources.list 更新源列表包: #apt-get update 更新系统软件: #apt-get upgrade #官方 ...

  10. jq 选项卡

    <!doctype html> <html> <head> <meta charset="utf-8"> <style> ...