【cocos2d-x3.2游戏开发】 lua 类, 继承, 面向对象

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 = {
	house=1
}
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)
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

如果是一个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)
    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
时间: 2024-10-05 11:21:04

【cocos2d-x3.2游戏开发】 lua 类, 继承, 面向对象的相关文章

lua 类, 继承, 面向对象再次理解

本文转载于: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.wid

【Cocos2D研究院之游戏开发】

http://www.xuanyusong.com/archives/category/ios/cocos2d_game 分类目录归档:[Cocos2D研究院之游戏开发] 201211-19 Cocos2D研究院之打开全新ViewController与返回(八) 雨松MOMO [Cocos2D研究院之游戏开发] 围观5745次 17条评论          之前cocos2d的文章都是由魏凯同学维护,从今天开始我也会抽时间写点cocos2d的文章.最近在研究如何将IOS游戏与软件结合起来.通常游

cocos2dx游戏开发学习笔记3-lua面向对象分析

在lua中,可以通过元表来实现类.对象.继承等.与元表相关的方法有setmetatable().__index.getmetatable().__newindex. 具体什么是元表在这里就不细说了,网上很多介绍,这里主要讲与cocos2dx相关联的部分. 在lua-binding库中extern.lua里,有如下方法: --Create an class. function class(classname, super) local superType = type(super) local c

[Unity3D]Unity3D游戏开发Lua随着游戏的债券(于)

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 喜欢我的博客请记住我的名字:秦元培.我的博客地址是blog.csdn.net/qinyuanpei. 转载请注明出处,本文作者:

[Unity3D]Unity3D游戏开发Lua随着游戏的债券(在)

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 喜欢我的博客请记住我的名字:秦元培,我的博客地址是blog.csdn.net/qinyuanpei. 转载请注明出处,本文作者:

lua 类继承和实现

http://blog.csdn.net/ssihc0/article/details/7742323 Account={balance=0}; --新建了一个对像,他有一个属性balance function Account:new(o) --这里的 :new(o) 中的冒号,代码可以省略self ,在访问的时候object:new(o) 如果是点号 :new(o) 就应改成 .new(self,o) 在访问的时候 object.(object,o) o= o or {} setmetatab

史上最全最完整的IOS 游戏开发 PDF电子书定制下载

<iOS 5游戏开发>作者:(新西兰)James·Sugrue著 页数:191 出版社:北京市:人民邮电出版社 出版日期:2012.08 简介:<iOS5游戏开发>是一本iOS5游戏开发的基础入门书.全书使用通俗易懂的简单实例,带领读者经历构建经典动作游戏的整个周期.读者在本书的阅读过程中,将经历从开发概念.规划设计一直到编写实际代码的全过过程.本书的每一章,都将演示游戏创建过程中的一个逻辑步骤,读者将在其中学习如何创建Sprite,用触摸屏.重力感应器和屏幕游戏棒控制玩家角色等-

6、Cocos2dx 3.0游戏开发找小三之游戏的基本概念

重开发者的劳动成果,转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/27689713 郝萌主友情提示: 人是习惯的产物,当你习惯快乐时,记忆里的不愉快就消失了. 游戏开始之前 经过之前的学习,我们已经可以开发一个最基本的 Cocos2d-x 游戏了,这个游戏包括一张背景图片和一个退出游戏的按 钮,但是这距离完成一个完整.实用的游戏还很遥远.在这一章节中,我们将首先抛开 Cocos2d,介绍游戏开发的基本概念,然后结合 Co

6、Cocos2dx 3.0游戏开发的基本概念找个小三场比赛

重开发人员的劳动成果,转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/27689713 郝萌主友情提示: 人是习惯的产物,当你习惯快乐时.记忆里的不愉快就消失了. 游戏開始之前 经过之前的学习,我们已经能够开发一个最主要的 Cocos2d-x 游戏了,这个游戏包含一张背景图片和一个退出游戏的按 钮,可是这距离完毕一个完整.有用的游戏还非常遥远.在这一章节中,我们将首先抛开 Cocos2d,介绍游戏开发的基本概念.然后结合