转自: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. dos 实用命令收集

    隐藏文件夹: H:\>attrib gho +h +s +r 解决win2012服务器上网慢:netsh int tcp set global  ecn=disable

  2. linux log4j 使用

    1.首先到Apache官网下载log4j.jar文件http://logging.apache.org/log4j/1.2/download.html 引用到eclipse项目里面 2.在src目录下 ...

  3. linux下valgrind的使用概述

    Valgrind简介: Valgrind是动态分析工具的框架.有很多Valgrind工具可以自动的检测许多内存管理和多进程/线程的bugs,在细节上剖析你的程序.你也可以利用Valgrind框架来实现 ...

  4. java 学习资料

    最近一直在从java基础开始学习java,感觉个人学习思路还是比较混乱的. 看到Java工程师成神之路中介绍了需要学习的知识点,并在<成神之路系列文章>中分章分节的开始介绍其中所有的知识点 ...

  5. As3 常用日期工具

    package com.lj.utils { import mx.controls.DateField; import mx.controls.dataGridClasses.DataGridColu ...

  6. eclipse 恢复被删除的文件

    即使你在项目中删除了某一文件,该文件的相关信息仍会保存在本地历史记录中.这就使得你可以恢复那些在项目或文件夹中已被删除的文件.如果恢复某一被删除的文件,则首先在Navigator视图中选择该文件先前所 ...

  7. 【转】asp.net发布到IIS中出现错误:处理程序“PageHandlerFactory-Integrated”在其模块列表中有一个错误模块“ManagedPipelineHandler”

    原文:http://blog.csdn.net/mazhaojuan/article/details/7660657 开发web项目时需要安装IIS,在安装好IIS的Windows7本上发布asp.n ...

  8. Sunrise Release Version History

    Sunrise Release Version History 1.4.1.0 1.1.0.0 1.0.1.0

  9. visual assistent 过期

    VA功能超级好使,下载的一般都有时间限制,但又不想买正版. 我的是32位系统 vs2008: 将VA_X.dll文件拷到 (x86)C:\Program Files\Visual Assist X\ ...

  10. Code-first示例

    首先创建一个空数据库 在vs2013中添加数据库类,按提示操作一直下一步   添加完以后,数据库类的代码 namespace mvctest.Models { using System; using ...