本文转自:http://www.voidcn.com/article/p-fwzpqsob-xy.html? 感谢作者的分享
1.lua中的类
? ? lua中其实是没有类的,有的只是表(table),而类之间的继承也就是将父类的表连到了一起,派生类中没有找到的属性和方法就通过元表查找父类
2.lua中类的属性
? ?classA = {width =10,height=10}
? ?classA={}
? ?classA.width=10
? ?classA.height=10?
? ?两种方法都可以,通过点self.width统一调用
3.类方法
- function?Box:collsion()??
- ????--?默认第一个参数隐藏传递self,可以通过self.xxx?调用属性和方法??
- end??
- ??
- function?Box.create(self)??
- ????--必须手动传递参数self,否则无法用self.xxx调用属性和方法??
- end??
函数的声明和调用可以用":"和".",属性调用全部用点"."
4.类与元表的用法
lua查找一个表元素时的规则,其实就是如下3个步骤:
? 4.1.在表中查找,如果找到,返回该元素,找不到则继续
? 4.2.判断该表是否有元表,如果没有元表,返回nil,有元表则继续
? 4.3.判断元表有没有__index方法,如果__index方法为nil,则返回nil;如果__index方法是一个表,则重复1、2、3;如果__index方法是一个函数,则返回该函数的返回值
例如:
father?=?{??
- ????house=1??
- }??
- son?=?{??
- ????car=1??
- }??
- setmetatable(son,?father)?--把son的metatable设置为father??
- print(son.house)??
输出结果是nil,如果代码改为
father.__index?=?father?--?把father的__index方法指向自己??
- son?=?{??
- ????car=1??
- setmetatable(son,?father)??
- print(son.house)??
输出的结果就为1了
这就解释了为什么我们经常在cocos2dx的类中经常见到如下
local?Box?=?class("Box",?function(filename)??
- ????????return?cc.Sprite:create(filename)??
- ????end)??
- Box.__index?=?Box??
设置Box的元表的__index方法为自己,当派生类"SmallBox"派生自"Box",如果在SmallBox中查找不到的属性和方法,就检索元表,当然不是直接从元表中直接检索,是检索元表下的__index,如果__index为nil,则返回nil,如果__index是一个表,那么就到__index方法所指的表中查找对应的属性和方法
具体可以参考:Lua查找表元素过程(元表、__index方法是如何工作的)
5.Cocos2dx中的类
lua没有面向对象一说,cocos为我们准备了class的lua端函数,我们参考quick的class函数,里面还有对应的例子
--[[--??
- 创建一个类??
- ~~~?lua??
- --?定义名为?Shape?的基础类??
- local?Shape?=?class("Shape")??
- ??
- --?ctor()?是类的构造函数,在调用?Shape.new()?创建?Shape?对象实例时会自动执行??
- function?Shape:ctor(shapeName)??
- ????self.shapeName?=?shapeName??
- ????printf("Shape:ctor(%s)",?self.shapeName)??
- end??
- --?为?Shape?定义个名为?draw()?的方法??
- function?Shape:draw()??
- ????printf("draw?%s",?self.shapeName)??
- --??
- --?Circle?是?Shape?的继承类??
- local?Circle?=?class("Circle",?Shape)??
- function?Circle:ctor()??
- ????--?如果继承类覆盖了?ctor()?构造函数,那么必须手动调用父类构造函数??
- ????--?类名.super?可以访问指定类的父类??
- ????Circle.super.ctor(self,?"circle")??
- ????self.radius?=?100??
- function?Circle:setRadius(radius)??
- ????self.radius?=?radius??
- --?覆盖父类的同名方法??
- function?Circle:draw()??
- ????printf("draw?%s,?raidus?=?%0.2f",?self.shapeName,?self.raidus)??
- --??
- local?Rectangle?=?class("Rectangle",248)"> function?Rectangle:ctor()??
- ????Rectangle.super.ctor(self,?"rectangle")??
- local?circle?=?Circle.new()?????????????--?输出:?Shape:ctor(circle)??
- circle:setRaidus(200)??
- circle:draw()???????????????????????????--?输出:?draw?circle,?radius?=?200.00??
- local?rectangle?=?Rectangle.new()???????--?输出:?Shape:ctor(rectangle)??
- rectangle:draw()????????????????????????--?输出:?draw?rectangle??
- ~~~??
- ###?高级用法??
- class()?除了定义纯?Lua?类之外,还可以从?C++?对象继承类。??
- 比如需要创建一个工具栏,并在添加按钮时自动排列已有的按钮,那么我们可以使用如下的代码:??
- --?从?cc.Node?对象派生?Toolbar?类,该类具有?cc.Node?的所有属性和行为??
- local?Toolbar?=?class("Toolbar",?function()??
- ????return?display.newNode()?--?返回一个?cc.Node?对象??
- end)??
- --?构造函数??
- function?Toolbar:ctor()??
- ????self.buttons?=?{}?--?用一个?table?来记录所有的按钮??
- --?添加一个按钮,并且自动设置按钮位置??
- function?Toolbar:addButton(button)??
- ????--?将按钮对象加入?table??
- ????self.buttons[#self.buttons?+?1]?=?button??
- ????--?添加按钮对象到?cc.Node?中,以便显示该按钮??
- ????--?因为?Toolbar?是从?cc.Node?继承的,所以可以使用?addChild()?方法??
- ????self:addChild(button)??
- ????--?按照按钮数量,调整所有按钮的位置??
- ????local?x?=?0??
- ????for?_,?button?in?ipairs(self.buttons)?do??
- ????????button:setPosition(x,?0)??
- ????????--?依次排列按钮,每个按钮之间间隔?10?点??
- ????????x?=?x?+?button:getContentSize().width?+?10??
- ????end??
- class()?的这种用法让我们可以在?C++?对象基础上任意扩展行为。??
- 既然是继承,自然就可以覆盖?C++?对象的方法:??
- function?Toolbar:setPosition(x,?y)??
- ????--?由于在?Toolbar?继承类中覆盖了?cc.Node?对象的?setPosition()?方法??
- ????--?所以我们要用以下形式才能调用到?cc.Node?原本的?setPosition()?方法??
- ????getmetatable(self).setPosition(self,?x,?y)??
- ????printf("x?=?%0.2f,?y?=?%0.2f",?y)??
- **注意:**?Lua?继承类覆盖的方法并不能从?C++?调用到。也就是说通过?C++?代码调用这个?cc.Node?对象的?setPosition()?方法时,并不会执行我们在?Lua?中定义的?Toolbar:setPosition()?方法。??
- @param?string?classname?类名??
- @param?[mixed?super]?父类或者创建对象实例的函数??
- @return?table??
- ]]??
- function?class(classname,?super)??
- ????local?superType?=?type(super)??
- ????local?cls??
- if?superType?~=?"function"?and?superType?~=?"table"?then??
- ????????superType?=?nil??
- ????????super?=?nil??
- if?superType?==?"function"?or?(super?and?super.__ctype?==?1)?then??
- ????????--?inherited?from?native?C++?Object??
- ????????cls?=?{}??
- if?superType?==?"table"?then??
- ????????????--?copy?fields?from?super??
- ????????????for?k,v?in?pairs(super)?do?cls[k]?=?v?end??
- ????????????cls.__create?=?super.__create??
- ????????????cls.super????=?super??
- ????????else??
- ????????????cls.__create?=?super??
- ????????????cls.ctor?=?function()?end??
- ????????end??
- ????????cls.__cname?=?classname??
- ????????cls.__ctype?=?1??
- ????????function?cls.new(...)??
- ????????????local?instance?=?cls.__create(...)??
- ????????????--?copy?fields?from?class?to?native?object??
- do?instance[k]?=?v?end??
- ????????????instance.class?=?cls??
- ????????????instance:ctor(...)??
- ????????????return?instance??
- else??
- ????????--?inherited?from?Lua?Object??
- if?super?then??
- ????????????cls?=?{}??
- ????????????setmetatable(cls,?{__index?=?super})??
- ????????????cls.super?=?super??
- ????????????cls?=?{ctor?=?function()?end}??
- ????????cls.__ctype?=?2?--?lua??
- ????????cls.__index?=?cls??
- ????????function?cls.new(...)??
- ????????????local?instance?=?setmetatable({},?cls)??
- ????????????instance.class?=?cls??
- ????????????instance:ctor(...)??
- return?instance??
- ????????end??
- return?cls??
- end??
传入是一个父类的话,会调用cls.new函数,然后创建实例,调用ctor构造函数
6. 调用一个实例:
假设派生自一个cocos的类 Sprite
--?class可以传1、2个参数??
- --?@param?类名,内部做记录而已,一般和返回的类名一致即可??
- --?@param?如果传参数2?使用当前函数作为构造函数?如果没参数2?默认的构造函数??
- local?Box?=?return?cc.Sprite:create(filename)??
- ????end)??
- --?设置元彪?更改元表默认的元方法??
- --?访问table中不存在的字段时,解释器查找__index的元方法,否则返回nil??
- --?多用于继承?http:??
- Box.__index?=?Box??
- Box.isDead?=?false??????--定义属性??
- --?构造函数(会自动调用)??
- --?外界构造时可以传任意参数XXX. function?Box:ctor(pic_path)??
- ????local?function?onNodeEvent(event)??
- if?"enter"?==?event?then??
- ????????????Box:onEnter(pic_path)??
- ????????elseif?"exit"?==?event?then??
- ????????????Box:onExit()??
- ????end??
- ????self:registerScriptHandler(onNodeEvent)??
- ????local?function?onUpdate()??
- ????self:scheduleUpdateWithPriorityLua(onUpdate,?0)??
- function?Box:onEnter(pic_path)??
- function?Box:onExit()??
- function?Box.create(parent,?position)??
- ????local?box?=?Box.New("data/box.png")??
- ????parent:addChild(box)??
- return?box??
- return?Box??
如果是一个table,可以直接使用
local?Bomb?=?class("Bomb")??
7.我们常见cocos2dx的例子中有大量的extend和tolua.getpeer用法如下:
local?TimelineTestScene?=?class("TimelineTestScene")??
- TimelineTestScene.__index?=?TimelineTestScene??
- function?TimelineTestScene.extend(target)??
- ????local?t?=?tolua.getpeer(target)??
- if?not?t?then??
- ????????t?=?{}??
- ????????tolua.setpeer(target,?t)??
- ????setmetatable(t,?TimelineTestScene)??
- return?target??
- function?TimelineTestScene.create()??
- ????local?scene?=?TimelineTestScene.extend(cc.Scene:create())??
- return?scene?????
- end??
用的时tolua.getpeer,其实它的功能就相当于调用了class,所以请远离extend吧
class("TimelineTestScene",?cc.Scene)??
- TimelineTestScene.__index?=?TimelineTestScene ?
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|