前段时间开始学习cocos2d-x,后面会陆续写一些cocos2d-x方面的东西。由于cocos2d-x支持lua脚本绑定,所以我们的项目是C++与lua混用,要求运行时效率高及内存占用少的部分使用C++,而那些需要动态更新的部分使用lua来写。
lua虽说是脚本语言,但也可以实现类(class)和继承的概念。具体到cocos2d-x,是用{cocos2d-x根目录}/samples/Lua/TestLua/Resources/luaScript/extern.lua里的class方法来实现的。
刚开始写lua的时候不知道可以直接创建一个lua类继承C++(C++对象在lua里都是userdata),就在lua对象里方一个layer或者node属性来访问userdata对象。
类似于下面的代码:
1
2
3
4
5
6
|
local
MyLayer
=
class
(
"MyLayer"
)
function
MyLayer
:
ctor
(
)
self
.
layer
=
CCLayer
:
create
(
)
end
return
MyLayer
|
这样的代码,每次添加到显示对象的时候,都不能直接addChild
,必须要addChild(myLayer.layer)
才行,很麻烦,后来问了老大才知道原来lua类可以直接继承C++类(userdada)的,于是就把上面的代码改成了下面的样子。
1
2
3
4
5
|
local
MyLayer
=
class
(
"MyLayer"
,
function
(
)
return
CCLayer
:
create
(
)
end
)
return
MyLayer
|
这样就可以直接addChild(myLayer)
,并且可以直接调用基类CCLayer
的方法,很方便。
今天用lua写了一个动态的组件,显示的时候总是会动啊动的,隐藏的时候当然要让它停下来以节省资源,毫无疑问,我需要为其添加start()
和stop()
两个方法。在设置visible的时候显示的调用下start和stop方法就可以啦。但是老大说这个不方便,直接在调用setVisible的时候在组件内部start或者stop,经过仔细研究lua继承C++类(userdata)的class函数,并测试后终于搞定了lua类覆盖C++基类的方法,原理就是构造的时候先保存C++方法的指针,后面调用时候就跟C++中一样。
示例代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
local
_setVisible
=
nil
local
MyLayer
=
class
(
"MyLayer"
,
function
(
)
local
layer
=
CCLayer
:
create
(
)
--
save
c
++
member
method
point
.
_setVisible
=
layer
.
setVisible
return
layer
end
)
--
override
CCLayer
::
setVisible
function
MyLayer
:
setVisible
(
visible
)
--
invoke
CCLayer
::
setVisible
_setVisible
(
self
,
visible
)
--
to
do
something
.
end
return
MyLayer
|
之前使用metatable来调用C++方法的时候出现了点问题就以为不能使用metatable的方式调用,~~后面再次测试后发现是可以正常使用的~~。相对于先保存引用的方式,通过metatable调用的方式更简单些。
经过再次研究代码后发现通过metatable调用C++类成员函数有限制,因为只有在lua绑定(pkg文件)的时候明确定义了的成员函数才会直接出现在metatable中,而C++的基类里的成员函数在其metatable的metatable中,继承关系越深,需要查找的metatable越多。
示例代码如下:
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
|
--
获取基类的某个方法
--
table
C
++类或者
lua
table
--
methodName
函数名,也可以是成员变量名
--
return
基类的函数或成员变量值(如果
methodName为变量名)
--
nil
表示找不到
local
function
getSuperMethod
(
table
,
methodName
)
local
mt
=
getmetatable
(
table
)
local
method
=
nil
while
mt
and
not
method
do
method
=
mt
[
methodName
]
if
not
method
then
local
index
=
mt
.
__index
if
index
and
type
(
index
)
==
"function"
then
method
=
index
(
mt
,
methodName
)
elseif
index
and
type
(
index
)
==
"table"
then
method
=
index
[
methodName
]
end
end
mt
=
getmetatable
(
mt
)
end
return
method
end
local
MyLayer
=
class
(
"MyLayer"
,
function
(
)
return
CCLayer
:
create
(
)
end
)
--
override
CCLayer
::
setVisible
function
MyLayer
:
setVisible
(
visible
)
--
invoke
CCLayer
::
setVisible
getSuperMethod
(
self
,
"setVisible"
)
(
self
,
visible
)
--
to
do
something
.
end
return
MyLayer
|