来自:http://blog.csdn.net/hapiman11/article/details/39271017
1.lua中的类
lua中其实是没有类的,有的只是表(table),而类之间的继承也就是将父类的表连到了一起,派生类中没有找到的属性和方法就通过元表查找父类
2.lua中类的属性
classA = {width =10, height=10}
classA={}
classA.width=10
classA.height=10
两种方法都可以,通过点self.width统一调用
3.类方法
1.
function Box:collsion()
2.
-- 默认第一个参数隐藏传递self,可以通过self.xxx 调用属性和方法
3.
end
4.
5.
function Box.create(self)
6.
--必须手动传递参数self,否则无法用self.xxx调用属性和方法
7.
end
4.类与元表的用法
lua查找一个表元素时的规则,其实就是如下3个步骤:
4.1.在表中查找,如果找到,返回该元素,找不到则继续
4.2.判断该表是否有元表,如果没有元表,返回nil,有元表则继续
4.3.判断元表有没有__index方法,如果__index方法为nil,则返回nil;如果__index方法是一个表,则重复1、2、3;如果__index方法是一个函数,则返回该函数的返回值
例如:
1.
father = {
2.
house=
1
3.
}
4.
son = {
5.
car=
1
6.
}
7.
setmetatable(son, father) --把son的metatable设置为father
8.
print(son.house)
01.
father = {
02.
house=
1
03.
}
04.
father.__index = father -- 把father的__index方法指向自己
05.
son = {
06.
car=
1
07.
}
08.
setmetatable(son, father)
09.
print(son.house)
这就解释了为什么我们经常在cocos2dx的类中经常见到如下
1.
local Box =
class
(
"Box"
, function(filename)
2.
return
cc.Sprite:create(filename)
3.
end)
4.
5.
Box.__index = Box
具体可以参考:Lua查找表元素过程(元表、__index方法是如何工作的)
5.Cocos2dx中的类
lua没有面向对象一说,cocos为我们准备了class的lua端函数,我们参考quick的class函数,里面还有对应的例子
001.
--[[--
002.
003.
创建一个类
004.
005.
~~~ lua
006.
007.
-- 定义名为 Shape 的基础类
008.
local Shape =
class
(
"Shape"
)
009.
010.
-- ctor() 是类的构造函数,在调用 Shape.
new
() 创建 Shape 对象实例时会自动执行
011.
function Shape:ctor(shapeName)
012.
self.shapeName = shapeName
013.
printf(
"Shape:ctor(%s)"
, self.shapeName)
014.
end
015.
016.
-- 为 Shape 定义个名为 draw() 的方法
017.
function Shape:draw()
018.
printf(
"draw %s"
, self.shapeName)
019.
end
020.
021.
--
022.
023.
-- Circle 是 Shape 的继承类
024.
local Circle =
class
(
"Circle"
, Shape)
025.
026.
function Circle:ctor()
027.
-- 如果继承类覆盖了 ctor() 构造函数,那么必须手动调用父类构造函数
028.
-- 类名.
super
可以访问指定类的父类
029.
Circle.
super
.ctor(self,
"circle"
)
030.
self.radius =
100
031.
end
032.
033.
function Circle:setRadius(radius)
034.
self.radius = radius
035.
end
036.
037.
-- 覆盖父类的同名方法
038.
function Circle:draw()
039.
printf(
"draw %s, raidus = %0.2f"
, self.shapeName, self.raidus)
040.
end
041.
042.
--
043.
044.
local Rectangle =
class
(
"Rectangle"
, Shape)
045.
046.
function Rectangle:ctor()
047.
Rectangle.
super
.ctor(self,
"rectangle"
)
048.
end
049.
050.
--
051.
052.
local circle = Circle.
new
() -- 输出: Shape:ctor(circle)
053.
circle:setRaidus(
200
)
054.
circle:draw() -- 输出: draw circle, radius =
200.00
055.
056.
local rectangle = Rectangle.
new
() -- 输出: Shape:ctor(rectangle)
057.
rectangle:draw() -- 输出: draw rectangle
058.
059.
~~~
060.
061.
### 高级用法
062.
063.
class
() 除了定义纯 Lua 类之外,还可以从 C++ 对象继承类。
064.
065.
比如需要创建一个工具栏,并在添加按钮时自动排列已有的按钮,那么我们可以使用如下的代码:
066.
067.
~~~ lua
068.
069.
-- 从 cc.Node 对象派生 Toolbar 类,该类具有 cc.Node 的所有属性和行为
070.
local Toolbar =
class
(
"Toolbar"
, function()
071.
return
display.newNode() -- 返回一个 cc.Node 对象
072.
end)
073.
074.
-- 构造函数
075.
function Toolbar:ctor()
076.
self.buttons = {} -- 用一个 table 来记录所有的按钮
077.
end
078.
079.
-- 添加一个按钮,并且自动设置按钮位置
080.
function Toolbar:addButton(button)
081.
-- 将按钮对象加入 table
082.
self.buttons[#self.buttons +
1
] = button
083.
084.
-- 添加按钮对象到 cc.Node 中,以便显示该按钮
085.
-- 因为 Toolbar 是从 cc.Node 继承的,所以可以使用 addChild() 方法
086.
self:addChild(button)
087.
088.
-- 按照按钮数量,调整所有按钮的位置
089.
local x =
0
090.
for
_, button in ipairs(self.buttons)
do
091.
button:setPosition(x,
0
)
092.
-- 依次排列按钮,每个按钮之间间隔
10
点
093.
x = x + button:getContentSize().width +
10
094.
end
095.
end
096.
097.
~~~
098.
099.
class
() 的这种用法让我们可以在 C++ 对象基础上任意扩展行为。
100.
101.
既然是继承,自然就可以覆盖 C++ 对象的方法:
102.
103.
~~~ lua
104.
105.
function Toolbar:setPosition(x, y)
106.
-- 由于在 Toolbar 继承类中覆盖了 cc.Node 对象的 setPosition() 方法
107.
-- 所以我们要用以下形式才能调用到 cc.Node 原本的 setPosition() 方法
108.
getmetatable(self).setPosition(self, x, y)
109.
110.
printf(
"x = %0.2f, y = %0.2f"
, x, y)
111.
end
112.
113.
~~~
114.
115.
**注意:** Lua 继承类覆盖的方法并不能从 C++ 调用到。也就是说通过 C++ 代码调用这个 cc.Node 对象的 setPosition() 方法时,并不会执行我们在 Lua 中定义的 Toolbar:setPosition() 方法。
116.
117.
@param
string classname 类名
118.
@param
[mixed
super
] 父类或者创建对象实例的函数
119.
120.
@return
table
121.
122.
]]
123.
function
class
(classname,
super
)
124.
local superType = type(
super
)
125.
local cls
126.
127.
if
superType ~=
"function"
and superType ~=
"table"
then
128.
superType = nil
129.
super
= nil
130.
end
131.
132.
if
superType ==
"function"
or (
super
and
super
.__ctype ==
1
) then
133.
-- inherited from
native
C++ Object
134.
cls = {}
135.
136.
if
superType ==
"table"
then
137.
-- copy fields from
super
138.
for
k,v in pairs(
super
)
do
cls[k] = v end
139.
cls.__create =
super
.__create
140.
cls.
super
=
super
141.
else
142.
cls.__create =
super
143.
cls.ctor = function() end
144.
end
145.
146.
cls.__cname = classname
147.
cls.__ctype =
1
148.
149.
function cls.
new
(...)
150.
local instance = cls.__create(...)
151.
-- copy fields from
class
to
native
object
152.
for
k,v in pairs(cls)
do
instance[k] = v end
153.
instance.
class
= cls
154.
instance:ctor(...)
155.
return
instance
156.
end
157.
158.
else
159.
-- inherited from Lua Object
160.
if
super
then
161.
cls = {}
162.
setmetatable(cls, {__index =
super
})
163.
cls.
super
=
super
164.
else
165.
cls = {ctor = function() end}
166.
end
167.
168.
cls.__cname = classname
169.
cls.__ctype =
2
-- lua
170.
cls.__index = cls
171.
172.
function cls.
new
(...)
173.
local instance = setmetatable({}, cls)
174.
instance.
class
= cls
175.
instance:ctor(...)
176.
return
instance
177.
end
178.
end
179.
180.
return
cls
181.
end
传入是一个父类的话,会调用cls.new函数,然后创建实例,调用ctor构造函数
6. 调用一个实例:
假设派生自一个cocos的类 Sprite
01.
--
class
可以传
1
、
2
个参数
02.
--
@param
类名,内部做记录而已,一般和返回的类名一致即可
03.
--
@param
如果传参数
2
使用当前函数作为构造函数 如果没参数
2
默认的构造函数
04.
local Box =
class
(
"Box"
, function(filename)
05.
return
cc.Sprite:create(filename)
06.
end)
07.
08.
-- 设置元彪 更改元表默认的元方法
09.
-- 访问table中不存在的字段时,解释器查找__index的元方法,否则返回nil
10.
-- 多用于继承 http:
//blog.csdn.net/q277055799/article/details/8463883
11.
Box.__index = Box
12.
Box.isDead =
false
--定义属性
13.
14.
-- 构造函数(会自动调用)
15.
-- 外界构造时可以传任意参数XXX.
new
(...)
16.
function Box:ctor(pic_path)
17.
local function onNodeEvent(event)
18.
if
"enter"
== event then
19.
Box:onEnter(pic_path)
20.
elseif
"exit"
== event then
21.
Box:onExit()
22.
end
23.
end
24.
25.
self:registerScriptHandler(onNodeEvent)
26.
27.
local function onUpdate()
28.
29.
end
30.
self:scheduleUpdateWithPriorityLua(onUpdate,
0
)
31.
32.
end
33.
34.
function Box:onEnter(pic_path)
35.
end
36.
37.
function Box:onExit()
38.
end
39.
40.
41.
function Box.create(parent, position)
42.
local box = Box.New(
"data/box.png"
)
43.
parent:addChild(box)
44.
return
box
45.
end
46.
47.
return
Box
如果是一个table,可以直接使用
1.
local Bomb =
class
(
"Bomb"
)
7.我们常见cocos2dx的例子中有大量的extend和tolua.getpeer用法如下:
01.
local TimelineTestScene =
class
(
"TimelineTestScene"
)
02.
TimelineTestScene.__index = TimelineTestScene
03.
04.
function TimelineTestScene.extend(target)
05.
local t = tolua.getpeer(target)
06.
if
not t then
07.
t = {}
08.
tolua.setpeer(target, t)
09.
end
10.
setmetatable(t, TimelineTestScene)
11.
return
target
12.
end
13.
14.
function TimelineTestScene.create()
15.
local scene = TimelineTestScene.extend(cc.Scene:create())
16.
return
scene
17.
end
用的时tolua.getpeer,其实它的功能就相当于调用了class,所以请远离extend吧
1.
local TimelineTestScene =
class
(
"TimelineTestScene"
, cc.Scene)
2.
TimelineTestScene.__index = TimelineTestScene