注:文章出处 http://blog.csdn.net/teng_ontheway/article/details/38900211
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
- 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)
- father = {
- house=1
- }
- son = {
- car=1
- }
- setmetatable(son, father) --把son的metatable设置为father
- print(son.house)
- father = {
- house=1
- }
- father.__index = father -- 把father的__index方法指向自己
- son = {
- car=1
- }
- setmetatable(son, father)
- print(son.house)
- father = {
- house=1
- }
- father.__index = father -- 把father的__index方法指向自己
- son = {
- car=1
- }
- setmetatable(son, father)
- print(son.house)
这就解释了为什么我们经常在cocos2dx的类中经常见到如下
- local Box = class("Box", function(filename)
- return cc.Sprite:create(filename)
- end)
- Box.__index = Box
- local Box = class("Box", function(filename)
- return cc.Sprite:create(filename)
- end)
- Box.__index = Box
具体可以参考: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)
- end
- --
- -- Circle 是 Shape 的继承类
- local Circle = class("Circle", Shape)
- function Circle:ctor()
- -- 如果继承类覆盖了 ctor() 构造函数,那么必须手动调用父类构造函数
- -- 类名.super 可以访问指定类的父类
- Circle.super.ctor(self, "circle")
- self.radius = 100
- end
- function Circle:setRadius(radius)
- self.radius = radius
- end
- -- 覆盖父类的同名方法
- function Circle:draw()
- printf("draw %s, raidus = %0.2f", self.shapeName, self.raidus)
- end
- --
- local Rectangle = class("Rectangle", Shape)
- function Rectangle:ctor()
- Rectangle.super.ctor(self, "rectangle")
- end
- --
- 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++ 对象继承类。
- 比如需要创建一个工具栏,并在添加按钮时自动排列已有的按钮,那么我们可以使用如下的代码:
- ~~~ lua
- -- 从 cc.Node 对象派生 Toolbar 类,该类具有 cc.Node 的所有属性和行为
- local Toolbar = class("Toolbar", function()
- return display.newNode() -- 返回一个 cc.Node 对象
- end)
- -- 构造函数
- function Toolbar:ctor()
- self.buttons = {} -- 用一个 table 来记录所有的按钮
- end
- -- 添加一个按钮,并且自动设置按钮位置
- 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
- end
- ~~~
- class() 的这种用法让我们可以在 C++ 对象基础上任意扩展行为。
- 既然是继承,自然就可以覆盖 C++ 对象的方法:
- ~~~ lua
- 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", x, y)
- end
- ~~~
- **注意:** 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
- end
- 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
- for k,v in pairs(cls) do instance[k] = v end
- instance.class = cls
- instance:ctor(...)
- return instance
- end
- else
- -- inherited from Lua Object
- if super then
- cls = {}
- setmetatable(cls, {__index = super})
- cls.super = super
- else
- cls = {ctor = function() end}
- end
- cls.__cname = classname
- cls.__ctype = 2 -- lua
- cls.__index = cls
- function cls.new(...)
- local instance = setmetatable({}, cls)
- instance.class = cls
- instance:ctor(...)
- return instance
- end
- end
- return cls
- end
- --[[--
- 创建一个类
- ~~~ 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)
- end
- --
- -- Circle 是 Shape 的继承类
- local Circle = class("Circle", Shape)
- function Circle:ctor()
- -- 如果继承类覆盖了 ctor() 构造函数,那么必须手动调用父类构造函数
- -- 类名.super 可以访问指定类的父类
- Circle.super.ctor(self, "circle")
- self.radius = 100
- end
- function Circle:setRadius(radius)
- self.radius = radius
- end
- -- 覆盖父类的同名方法
- function Circle:draw()
- printf("draw %s, raidus = %0.2f", self.shapeName, self.raidus)
- end
- --
- local Rectangle = class("Rectangle", Shape)
- function Rectangle:ctor()
- Rectangle.super.ctor(self, "rectangle")
- end
- --
- 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++ 对象继承类。
- 比如需要创建一个工具栏,并在添加按钮时自动排列已有的按钮,那么我们可以使用如下的代码:
- ~~~ lua
- -- 从 cc.Node 对象派生 Toolbar 类,该类具有 cc.Node 的所有属性和行为
- local Toolbar = class("Toolbar", function()
- return display.newNode() -- 返回一个 cc.Node 对象
- end)
- -- 构造函数
- function Toolbar:ctor()
- self.buttons = {} -- 用一个 table 来记录所有的按钮
- end
- -- 添加一个按钮,并且自动设置按钮位置
- 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
- end
- ~~~
- class() 的这种用法让我们可以在 C++ 对象基础上任意扩展行为。
- 既然是继承,自然就可以覆盖 C++ 对象的方法:
- ~~~ lua
- 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", x, y)
- end
- ~~~
- **注意:** 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
- end
- 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
- for k,v in pairs(cls) do instance[k] = v end
- instance.class = cls
- instance:ctor(...)
- return instance
- end
- else
- -- inherited from Lua Object
- if super then
- cls = {}
- setmetatable(cls, {__index = super})
- cls.super = super
- else
- cls = {ctor = function() end}
- end
- cls.__cname = classname
- cls.__ctype = 2 -- lua
- cls.__index = cls
- function cls.new(...)
- local instance = setmetatable({}, cls)
- instance.class = cls
- instance:ctor(...)
- return instance
- end
- end
- return cls
- end
传入是一个父类的话,会调用cls.new函数,然后创建实例,调用ctor构造函数
6. 调用一个实例:
假设派生自一个cocos的类 Sprite
- -- class可以传1、2个参数
- -- @param 类名,内部做记录而已,一般和返回的类名一致即可
- -- @param 如果传参数2 使用当前函数作为构造函数 如果没参数2 默认的构造函数
- local Box = class("Box", function(filename)
- return cc.Sprite:create(filename)
- end)
- -- 设置元彪 更改元表默认的元方法
- -- 访问table中不存在的字段时,解释器查找__index的元方法,否则返回nil
- -- 多用于继承 http://blog.csdn.net/q277055799/article/details/8463883
- Box.__index = Box
- Box.isDead = false --定义属性
- -- 构造函数(会自动调用)
- -- 外界构造时可以传任意参数XXX.new(...)
- function Box:ctor(pic_path)
- local function onNodeEvent(event)
- if "enter" == event then
- Box:onEnter(pic_path)
- elseif "exit" == event then
- Box:onExit()
- end
- end
- self:registerScriptHandler(onNodeEvent)
- local function onUpdate()
- end
- self:scheduleUpdateWithPriorityLua(onUpdate, 0)
- end
- function Box:onEnter(pic_path)
- end
- function Box:onExit()
- end
- function Box.create(parent, position)
- local box = Box.New("data/box.png")
- parent:addChild(box)
- return box
- end
- return Box
- -- class可以传1、2个参数
- -- @param 类名,内部做记录而已,一般和返回的类名一致即可
- -- @param 如果传参数2 使用当前函数作为构造函数 如果没参数2 默认的构造函数
- local Box = class("Box", function(filename)
- return cc.Sprite:create(filename)
- end)
- -- 设置元彪 更改元表默认的元方法
- -- 访问table中不存在的字段时,解释器查找__index的元方法,否则返回nil
- -- 多用于继承 http://blog.csdn.net/q277055799/article/details/8463883
- Box.__index = Box
- Box.isDead = false --定义属性
- -- 构造函数(会自动调用)
- -- 外界构造时可以传任意参数XXX.new(...)
- function Box:ctor(pic_path)
- local function onNodeEvent(event)
- if "enter" == event then
- Box:onEnter(pic_path)
- elseif "exit" == event then
- Box:onExit()
- end
- end
- self:registerScriptHandler(onNodeEvent)
- local function onUpdate()
- end
- self:scheduleUpdateWithPriorityLua(onUpdate, 0)
- end
- function Box:onEnter(pic_path)
- end
- function Box:onExit()
- end
- function Box.create(parent, position)
- local box = Box.New("data/box.png")
- parent:addChild(box)
- return box
- end
- return Box
如果是一个table,可以直接使用
- local Bomb = class("Bomb")
- local Bomb = class("Bomb")
- 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)
- end
- setmetatable(t, TimelineTestScene)
- return target
- end
- function TimelineTestScene.create()
- local scene = TimelineTestScene.extend(cc.Scene:create())
- return scene
- end
- 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)
- end
- setmetatable(t, TimelineTestScene)
- return target
- end
- function TimelineTestScene.create()
- local scene = TimelineTestScene.extend(cc.Scene:create())
- return scene
- end
用的时tolua.getpeer,其实它的功能就相当于调用了class,所以请远离extend吧
- local TimelineTestScene = class("TimelineTestScene", cc.Scene)
- TimelineTestScene.__index = TimelineTestScene