您的位置:首页 > 移动开发 > Cocos引擎

cocos2dx +lua 面向对象

2015-09-09 16:00 519 查看
来自: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.类方法

 

view sourceprint?

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方法是一个函数,则返回该函数的返回值

例如:

 

view sourceprint?

1.
father = {

2.
    
house=
1

3.
}

4.
son = {

5.
    
car=
1

6.
}

7.
setmetatable(son, father) --把son的metatable设置为father

8.
print(son.house)


输出结果是nil,如果代码改为

 

 

view sourceprint?

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)


输出的结果就为1了

这就解释了为什么我们经常在cocos2dx的类中经常见到如下

 

 

view sourceprint?

1.
local Box = 
class
(
"Box"
,
function(filename)

2.
        
return
 
cc.Sprite:create(filename)

3.
    
end)

4.
 
 
5.
Box.__index = Box


设置Box的元表的__index方法为自己,当派生类"SmallBox"派生自"Box",如果在SmallBox中查找不到的属性和方法,就检索元表,当然不是直接从元表中直接检索,是检索元表下的__index,如果__index为nil,则返回nil,如果__index是一个表,那么就到__index方法所指的表中查找对应的属性和方法

 

具体可以参考:Lua查找表元素过程(元表、__index方法是如何工作的)

 

5.Cocos2dx中的类

lua没有面向对象一说,cocos为我们准备了class的lua端函数,我们参考quick的class函数,里面还有对应的例子

 

view sourceprint?

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

 

view sourceprint?

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,可以直接使用

 

 

view sourceprint?

1.
local Bomb = 
class
(
"Bomb"
)


 
7.我们常见cocos2dx的例子中有大量的extend和tolua.getpeer用法如下:

 

view sourceprint?

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吧

 

view sourceprint?

1.
local TimelineTestScene = 
class
(
"TimelineTestScene"
,
cc.Scene)

2.
TimelineTestScene.__index = TimelineTestScene
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: