quick cocos2dx基础(一):lua类及继承,class解析

时间:2025-04-08 21:18:45

    学习quick cocos2dx,首先必须要掌握基本的lua知识,在quick中,大量出现了类,继承以及class,因此个人认为必须对这一块有很好的理解。

    首先,先描述一下lua的自定义类的写法,这是从中注释中摘录出来的,个人觉得描述的比较详细。

    --[[--


创建一个类


~~~ lua


-- 定义名为 Shape 的基础类
local Shape = class("Shape")


-- ctor() 是类的构造函数,在调用 () 创建 Shape 对象实例时会自动执行
function Shape:ctor(shapeName)
    = shapeName
    printf("Shape:ctor(%s)", )
end


shapeName是类的一个成员变量,在lua中成员变量可以直接通过=shapeName来生成并同时赋值,不用先声明,另外,前面不用local修饰,用local修饰的是局部变量而不是成员变量,成员变量前面用self.


-- 为 Shape 定义个名为 draw() 的方法
function Shape:draw()
    printf("draw %s", )
end
--

-- Circle 是 Shape 的继承类
local Circle = class("Circle", Shape)
function Circle:ctor()
    -- 如果继承类覆盖了 ctor() 构造函数,那么必须手动调用父类构造函数
    -- 类名.super 可以访问指定类的父类
    (self, "circle")
    = 100
end


function Circle:setRadius(radius)
    = radius
end


-- 覆盖父类的同名方法
function Circle:draw()
    printf("draw %s, raidus = %0.2f", , )
end

--

local Rectangle = class("Rectangle", Shape)

function Rectangle:ctor()
    (self, "rectangle")
end


--


local circle = ()             -- 输出: Shape:ctor(circle)
circle:setRaidus(200)
circle:draw()                           -- 输出: draw circle, radius = 200.00


local rectangle = ()       -- 输出: Shape:ctor(rectangle)
rectangle:draw()                        -- 输出: draw rectangle


~~~

### 高级用法

class() 除了定义纯 Lua 类之外,还可以从 C++ 对象继承类。


比如需要创建一个工具栏,并在添加按钮时自动排列已有的按钮,那么我们可以使用如下的代码:


~~~ lua


-- 从 CCNode 对象派生 Toolbar 类,该类具有 CCNode 的所有属性和行为
local Toolbar = class("Toolbar", function()
    return () -- 返回一个 CCNode 对象
end)


-- 构造函数
function Toolbar:ctor()
    = {} -- 用一个 table 来记录所有的按钮
end


-- 添加一个按钮,并且自动设置按钮位置
function Toolbar:addButton(button)
    -- 将按钮对象加入 table
    [# + 1] = button


    -- 添加按钮对象到 CCNode 中,以便显示该按钮
    -- 因为 Toolbar 是从 CCNode 继承的,所以可以使用 addChild() 方法
    self:addChild(button)


    -- 按照按钮数量,调整所有按钮的位置
    local x = 0
    for _, button in ipairs() do
        button:setPosition(x, 0)
        -- 依次排列按钮,每个按钮之间间隔 10 点
        x = x + button:getContentSize().width + 10
    end
end


~~~


class() 的这种用法让我们可以在 C++ 对象基础上任意扩展行为。


既然是继承,自然就可以覆盖 C++ 对象的方法:


~~~ lua


function Toolbar:setPosition(x, y)
    -- 由于在 Toolbar 继承类中覆盖了 CCNode 对象的 setPosition() 方法
    -- 所以我们要用以下形式才能调用到 CCNode 原本的 setPosition() 方法
    getmetatable(self).setPosition(self, x, y)


    printf("x = %0.2f, y = %0.2f", x, y)
end


~~~


**注意:** Lua 继承类覆盖的方法并不能从 C++ 调用到。也就是说通过 C++ 代码调用这个 CCNode 对象的 setPosition() 方法时,并不会执行我们在 Lua 中定义的 Toolbar:setPosition() 方法。

函数class(classname, super)有两个参数,class的定义在framework中的中

参数1:classname,见名知意,类名

参数2:super


function class(classname, super)
    local superType = type(super)
    local cls


    --如果父类既不是函数也不是table则说明父类为空
    if superType ~= "function" and superType ~= "table" then
        superType = nil
        super = nil
    end


    --如果父类的类型是函数或者是C对象
    if superType == "function" or (super and super.__ctype == 1) then
        -- inherited from native C++ Object
        cls = {}


        --如果父类是表则复制成员并且设置这个类的继承信息
        --如果是函数类型则设置构造方法并且设置ctor函数
        if superType == "table" then
            -- copy fields from super
            for k,v in pairs(super) do cls[k] = v end
            cls.__create = super.__create
               = super
        else
            cls.__create = super
            = function() end
        end


        --设置类型的名称
        cls.__cname = classname
        cls.__ctype = 1


        --定义该类型的创建实例的函数为基类的构造函数后复制到子类实例
        --并且调用子数的ctor方法
        function (...)
            local instance = cls.__create(...)
            -- copy fields from class to native object
            for k,v in pairs(cls) do instance[k] = v end
            = cls
            instance:ctor(...)
            return instance
        end


    else
        --如果是继承自普通的lua表,则设置一下原型,并且构造实例后也会调用ctor方法
        -- inherited from Lua Object
        if super then
            cls = {}
            setmetatable(cls, {__index = super})
            = super
        else
            cls = {ctor = function() end}
        end


        cls.__cname = classname
        cls.__ctype = 2 -- lua
        cls.__index = cls


        function (...)
            local instance = setmetatable({}, cls)
            = cls
            instance:ctor(...)
            return instance
        end
    end


    return cls


end


的类型:superType = type(super)

可以为functiontable,当不为这两种类型的时候我们将之置为nil

function的时候,表示从C++对象继承

table的时候,还要看其__ctype值,1表示继承自C++对象;2表示继承自lua表对象

nil的时候,从lua表继承

一般情况下,superType为function的时候,表示继承的是一个C++对象,这个时候构造函数ctor里不需要调用父类的构造函数;其它情况,一般都需要在ctor里调用父类的构造函数。