转载自【黑米GameDev街区】 原文链接: http://www.himigame.com/lua-game/1343.html
在使用Cocos2d-x 时候,难免需要C/C++调用Lua函数、数据或Lua调用C/C++函数,那么本篇讲详细介绍C/C++与Lua之间的数据、函数交互。
首先让我们来简单了解几个Lua API函数:
int luaL_dofile (lua_State *L, const char *filename) :
加载并运行指定文件,没有错误返回0
void lua_settop (lua_State *L, int index):
参数允许传入任何可接受的索引以及 0 。 它将把堆栈的栈顶设为这个索引。 如果新的栈顶比原来的大,超出部分的新元素将被填为 nil 。 如果 index 为 0 ,把栈上所有元素移除。
void lua_getglobal (lua_State *L, const char *name):
把全局变量 name 里的值压入堆栈。
void lua_pop (lua_State *L, int n):
从堆栈中弹出 n
个元素。相当于清除!
void lua_pushstring (lua_State *L, const char *s):
把指针 s 指向的以零结尾的字符串压栈。 Lua 对这个字符串做一次内存拷贝(或是复用一个拷贝), 因此 s 处的内存在函数返回后,可以释放掉或是重用于其它用途。 字符串中不能包含有零字符;第一个碰到的零字符会认为是字符串的结束。
更多的API请参考:http://www.codingnow.com/2000/download/lua_manual.html
了解了以上几个函数,为了方便童鞋们使用,Himi直接贴出封装好的类 HclcData,其中主要包括如下几个功能:
1. C/C++ 调用 Lua 全局变量
2. C/C++ 调用 Lua 全局Table 某元素
3. C/C++ 调用 Lua 全局Table
4. C/C++ 调用 Lua 函数
5. Lua 调用C/C++ 函数
下面直接贴出代码:HclcData.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
//
// 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__) */
|
HclcData.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
|
//
// 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
(
)
-
&
gt
;
getLuaStack
(
)
-
&
gt
;
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
(
)
-
&
gt
;
getLuaStack
(
)
-
&
gt
;
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
(
)
-
&
gt
;
getLuaStack
(
)
-
&
gt
;
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
(
)
-
&
gt
;
getLuaStack
(
)
-
&
gt
;
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
(
)
-
&
gt
;
getLuaStack
(
)
-
&
gt
;
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
)
;
int
luaStr
=
(
int
)
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
(
)
-
&
gt
;
fullPathForFilename
(
fileName
)
.
c_str
(
)
;
}
HclcData
::
~
HclcData
(
)
{
CC_SAFE_DELETE
(
_shared
)
;
_shared
=
NULL
;
}
|
大家可以直接拿来用的,使用简单,测试如下:
首先C++测试代码:
1
2
3
4
5
6
7
8
9
10
11
12
|
#include "HclcData.h"
CCLOG
(
"Str = %s"
,
HclcData
::
sharedHD
(
)
-
&
gt
;
getLuaVarString
(
"Test.lua"
,
"luaStr"
)
)
;
CCLOG
(
"Str2 %s"
,
HclcData
::
sharedHD
(
)
-
&
gt
;
getLuaVarString
(
"Test.lua"
,
"luaStr2"
)
)
;
CCLOG
(
"age = %s"
,
HclcData
::
sharedHD
(
)
-
&
gt
;
getLuaVarOneOfTable
(
"Test.lua"
,
"luaTable"
,
"age"
)
)
;
CCLOG
(
"name = %s"
,
HclcData
::
sharedHD
(
)
-
&
gt
;
getLuaVarOneOfTable
(
"Test.lua"
,
"luaTable"
,
"name"
)
)
;
CCLOG
(
"sex = %s"
,
HclcData
::
sharedHD
(
)
-
&
gt
;
getLuaVarOneOfTable
(
"Test.lua"
,
"luaTable"
,
"sex"
)
)
;
CCLOG
(
"Table = %s"
,
HclcData
::
sharedHD
(
)
-
&
gt
;
getLuaVarTable
(
"Test.lua"
,
"luaTable"
)
)
;
CCLOG
(
"Call Lua Function Back: %s"
,
HclcData
::
sharedHD
(
)
-
&
gt
;
callLuaFunction
(
"Test.lua"
,
"luaLogString"
)
)
;
HclcData
::
sharedHD
(
)
-
&
gt
;
callCppFunction
(
"Test.lua"
)
;
HclcData
::
sharedHD
(
)
-
&
gt
;
callLuaFunction
(
"Test.lua"
,
"call_Cpp"
)
;
|
对应测试的Test.Lua文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
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
|
运行测试结果如下:
1
2
3
4
5
6
7
8
9
10
|
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
|
在Himi做这些交互时出现了如下错误:
1
|
“
PANIC
:
unprotected
error
in
call
to
Lua
API
(
attempt
to
index
a
nil
value
)
|
如下图:
最后Himi发现造成此问题的原因有两种情况:
1. 是你的lua文件位置路径!
细心的童鞋应该看到,每次我使用 luaL_dofile 函数时传入的都是调用了一个getFileFullPath的函数进行获取文件的完整路径!
在HclcData中包装了一个函数:
1
2
3
|
const
char
*
HclcData
::
getFileFullPath
(
const
char
*
fileName
)
{
return
CCFileUtils
::
sharedFileUtils
(
)
-
&
gt
;
fullPathForFilename
(
fileName
)
.
c_str
(
)
;
}
|
2. 如果你是cpp调用lua函数,那么你的这个lua函数不能是local的!
反之,如果你lua调用cpp函数,同理,cpp函数肯定是static的!
另外,如果你cpp调用lua,等同于重新加载了这个lua文件,是不同的对象!因此你应该建立一个新的lua文件,主要用于交互所用!
例如你a.lua中有一个tab的成员变量,那么你使用cpp调用lua函数后,这个tab是新的对象!
最后附上HclcData和Test.lua 下载地址:http://vdisk.weibo.com/s/y0zws
OK,本篇就到这里,有什么问题及时联系Himi!