cocos2dx lua 字符串转换成数值

2015年02月10日 17:32 0 点赞 0 评论 更新于 2025-11-21 16:12

在使用 Cocos2d-x 开发过程中,C/C++ 与 Lua 之间的数据和函数交互是常见需求。本文将详细介绍 C/C++ 与 Lua 之间的数据、函数交互,同时会介绍几个重要的 Lua API 函数,并给出封装好的类 HclcData 实现相应功能。

一、Lua API 函数介绍

以下是几个常用的 Lua API 函数:

  1. luaL_dofile
    • 函数原型int luaL_dofile (lua_State *L, const char *filename)
    • 功能:加载并运行指定文件,没有错误返回 0。
  2. lua_settop
    • 函数原型void lua_settop (lua_State *L, int index)
    • 功能:参数允许传入任何可接受的索引以及 0。它将把堆栈的栈顶设为这个索引。如果新的栈顶比原来的大,超出部分的新元素将被填为 nil。如果 index 为 0,把栈上所有元素移除。
  3. lua_getglobal
    • 函数原型void lua_getglobal (lua_State *L, const char *name)
    • 功能:把全局变量 name 里的值压入堆栈。
  4. lua_pop
    • 函数原型void lua_pop (lua_State *L, int n)
    • 功能:从堆栈中弹出 n 个元素,相当于清除操作。
  5. lua_pushstring
    • 函数原型void lua_pushstring (lua_State *L, const char *s)
    • 功能:把指针 s 指向的以零结尾的字符串压栈。Lua 对这个字符串做一次内存拷贝(或是复用一个拷贝),因此 s 处的内存在函数返回后,可以释放掉或是重用于其它用途。字符串中不能包含有零字符,第一个碰到的零字符会认为是字符串的结束。

二、封装类 HclcData 功能介绍

为了方便使用,封装了 HclcData 类,主要包括以下几个功能:

  1. C/C++ 调用 Lua 全局变量
  2. C/C++ 调用 Lua 全局 Table 某元素
  3. C/C++ 调用 Lua 全局 Table
  4. C/C++ 调用 Lua 函数
  5. Lua 调用 C/C++ 函数

2.1 HclcData.h 代码

// HclcData.h
// CppLua
// Created by Himi on 13 - 4 - 17.

#ifndef __CppLua__HclcData__
#define __CppLua__HclcData__

#include "cocos2d.h"
using namespace cocos2d;
using namespace std;

extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
};

class HclcData {
public:
static HclcData* sharedHD();

//------------ c++ -> lua ------------//
/*
getLuaVarString : 调用lua全局string
luaFileName = lua文件名
varName = 所要取Lua中的变量名
*/
const char* getLuaVarString(const char* luaFileName, const char* varName);

/*
getLuaVarOneOfTable : 调用lua全局table中的一个元素
luaFileName = lua文件名
varName = 所要取Lua中的table变量名
keyName = 所要取Lua中的table中某一个元素的Key
*/
const char* getLuaVarOneOfTable(const char* luaFileName, const char* varName, const char* keyName);

/*
getLuaVarTable : 调用lua全局table
luaFileName = lua文件名
varName = 所要取的table变量名
(注:返回的是所有的数据,开发者可以自己使用Map等处理)
*/
const char* getLuaVarTable(const char* luaFileName, const char* varName);

/*
callLuaFunction : 调用lua函数
luaFileName = lua文件名
functionName = 所要调用Lua中的的函数名
*/
const char* callLuaFunction(const char* luaFileName, const char* functionName);

//------------  lua -> c++ ------------//
void callCppFunction(const char* luaFileName);

private:
static int cppFunction(lua_State* ls);
static bool _isFirst;
static HclcData* _shared;
const char* getFileFullPath(const char* fileName);
~HclcData();
};

#endif /* defined(__CppLua__HclcData__) */

2.2 HclcData.cpp 代码

// HclcData.cpp
// CppLua
// Created by Himi on 13 - 4 - 17.

#include "HclcData.h"
#include "CCLuaEngine.h"

bool HclcData::_isFirst;
HclcData* HclcData::_shared;

HclcData* HclcData::sharedHD() {
if (!_isFirst) {
_shared = new HclcData();
}
return _shared;
}

const char* HclcData::getLuaVarString(const char* luaFileName, const char* varName) {
lua_State* ls = CCLuaEngine::defaultEngine()->getLuaStack()->getLuaState();
int isOpen = luaL_dofile(ls, getFileFullPath(luaFileName));
if (isOpen != 0) {
CCLOG("Open Lua Error: %i", isOpen);
return NULL;
}
lua_settop(ls, 0);
lua_getglobal(ls, varName);
int statesCode = lua_isstring(ls, 1);
if (statesCode != 1) {
CCLOG("Open Lua Error: %i", statesCode);
return NULL;
}
const char* str = lua_tostring(ls, 1);
lua_pop(ls, 1);
return str;
}

const char* HclcData::getLuaVarOneOfTable(const char* luaFileName, const char* varName, const char* keyName) {
lua_State* ls = CCLuaEngine::defaultEngine()->getLuaStack()->getLuaState();
int isOpen = luaL_dofile(ls, getFileFullPath(luaFileName));
if (isOpen != 0) {
CCLOG("Open Lua Error: %i", isOpen);
return NULL;
}
lua_getglobal(ls, varName);
int statesCode = lua_istable(ls, -1);
if (statesCode != 1) {
CCLOG("Open Lua Error: %i", statesCode);
return NULL;
}
lua_pushstring(ls, keyName);
lua_gettable(ls, -2);
const char* valueString = lua_tostring(ls, -1);
lua_pop(ls, -1);
return valueString;
}

const char* HclcData::getLuaVarTable(const char* luaFileName, const char* varName) {
lua_State* ls = CCLuaEngine::defaultEngine()->getLuaStack()->getLuaState();
int isOpen = luaL_dofile(ls, getFileFullPath(luaFileName));
if (isOpen != 0) {
CCLOG("Open Lua Error: %i", isOpen);
return NULL;
}
lua_getglobal(ls, varName);
int it = lua_gettop(ls);
lua_pushnil(ls);
string result = "";
while (lua_next(ls, it)) {
string key = lua_tostring(ls, -2);
string value = lua_tostring(ls, -1);
result = result + key + ":" + value + "\t";
lua_pop(ls, 1);
}
lua_pop(ls, 1);
return result.c_str();
}

const char* HclcData::callLuaFunction(const char* luaFileName, const char* functionName) {
lua_State* ls = CCLuaEngine::defaultEngine()->getLuaStack()->getLuaState();
int isOpen = luaL_dofile(ls, getFileFullPath(luaFileName));
if (isOpen != 0) {
CCLOG("Open Lua Error: %i", isOpen);
return NULL;
}
lua_getglobal(ls, functionName);
lua_pushstring(ls, "Himi");
lua_pushnumber(ls, 23);
lua_pushboolean(ls, true);
/*
lua_call
第一个参数:函数的参数个数
第二个参数:函数返回值个数
*/
lua_call(ls, 3, 1);
const char* iResult = lua_tostring(ls, -1);
return iResult;
}

void HclcData::callCppFunction(const char* luaFileName) {
lua_State* ls = CCLuaEngine::defaultEngine()->getLuaStack()->getLuaState();
/*
Lua调用的C++的函数必须是静态的
*/
lua_register(ls, "cppFunction", cppFunction);
int isOpen = luaL_dofile(ls, getFileFullPath(luaFileName));
if (isOpen != 0) {
CCLOG("Open Lua Error: %i", isOpen);
return;
}
}

int HclcData::cppFunction(lua_State* ls) {
int luaNum = (int)lua_tonumber(ls, 1);
const char* luaStr = lua_tostring(ls, 2);
CCLOG("Lua调用cpp函数时传来的两个参数: %i  %s", luaNum, luaStr);
/*
返给Lua的值
*/
lua_pushnumber(ls, 321);
lua_pushstring(ls, "Himi");
/*
返给Lua值个数
*/
return 2;
}

const char* HclcData::getFileFullPath(const char* fileName) {
return CCFileUtils::sharedFileUtils()->fullPathForFilename(fileName).c_str();
}

HclcData::~HclcData() {
CC_SAFE_DELETE(_shared);
_shared = NULL;
}

三、测试代码

3.1 C++ 测试代码

#include "HclcData.h"

CCLOG("Str = %s", HclcData::sharedHD()->getLuaVarString("Test.lua", "luaStr"));
CCLOG("Str2 %s", HclcData::sharedHD()->getLuaVarString("Test.lua", "luaStr2"));
CCLOG("age = %s", HclcData::sharedHD()->getLuaVarOneOfTable("Test.lua", "luaTable", "age"));
CCLOG("name = %s", HclcData::sharedHD()->getLuaVarOneOfTable("Test.lua", "luaTable", "name"));
CCLOG("sex = %s", HclcData::sharedHD()->getLuaVarOneOfTable("Test.lua", "luaTable", "sex"));
CCLOG("Table = %s", HclcData::sharedHD()->getLuaVarTable("Test.lua", "luaTable"));
CCLOG("Call Lua Function Back: %s", HclcData::sharedHD()->callLuaFunction("Test.lua", "luaLogString"));

HclcData::sharedHD()->callCppFunction("Test.lua");
HclcData::sharedHD()->callLuaFunction("Test.lua", "call_Cpp");

3.2 对应测试的 Test.lua 文件

luaStr = "I' m Himi"
luaStr2 = "are you ok!"
luaTable = {age = 23, name = "Himi", sex = "男"}

function luaLogString(_logStr, _logNum, _logBool)
print("Lua 脚本打印从C传来的字符串:", _logStr, _logNum, _logBool)
return "call lua function OK"
end

function call_Cpp(_logStr, _logNum, _logBool)
num, str = cppFunction(999, "I'm a lua string")
print("从cpp函数中获得两个返回值:", num, str)
end

四、测试结果

Cocos2d: Str = I' m Himi
Cocos2d: Str2 are you ok!
Cocos2d: age = 23
Cocos2d: name = Himi
Cocos2d: sex = 男
Cocos2d: Table = name:Himi  age:23  sex:男
Lua 脚本打印从C传来的字符串:   Himi    23  true
Cocos2d: Call Lua Function Back: call lua function OK
Cocos2d: Lua调用cpp函数时传来的两个参数: 999  I'm a lua string
从cpp函数中获得两个返回值: 321 Himi

五、常见错误及解决办法

在进行交互时,可能会出现如下错误:

“PANIC: unprotected error in call to Lua API (attempt to index a nil value)

造成此问题的原因通常是 lua 文件位置路径问题。开发者在使用 luaL_dofile 时,需要确保 lua 文件的路径正确。

作者信息

boke

boke

共发布了 3994 篇文章