加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Cocos2dx-lua -- 入门-class

发布时间:2020-12-14 16:57:34 所属栏目:百科 来源:网络整理
导读:Lua中没有类的概念,有的只有table表,而面向对象的实现只不过是将表与父类的表连在一起,没有某个变量的时候就去父类查找。cocos2dx-lua中有一个class函数实现了类的继承,包括了单继承和多重继承。 function class (classname,...) -- 参数一:要创建的类

Lua中没有类的概念,有的只有table表,而面向对象的实现只不过是将表与父类的表连在一起,没有某个变量的时候就去父类查找。cocos2dx-lua中有一个class函数实现了类的继承,包括了单继承和多重继承。

function class(classname,...)     -- 参数一:要创建的类名称,参数二:父类-可选参数,可以是table,function,userdata等
    local cls = {__cname = classname}

    local supers = {...}   
    for _,super in ipairs(supers) do    -- 遍历父类
        local superType = type(super)
        -- 父类如果不是第一个参数表示的类型的话,就输出第二个参数
        assert(superType == "nil" or superType == "table" or superType == "function",string.format("class() - create class "%s" with invalid super class type "%s"",classname,superType))

        if superType == "function" then
            assert(cls.__create == nil,string.format("class() - create class "%s" with more than one creating function",classname));
            -- 如果父类是个function的话,就让cls的create方法指向他
            cls.__create = super
        elseif superType == "table" then  -- 如果父类是table
            if super[".isclass"] then
                -- 如果父类是原生的cocos类,比如cc.Node,不是自己定义的类
                assert(cls.__create == nil,string.format("class() - create class "%s" with more than one creating function or native class",classname));
                cls.__create = function() return super:create() end
            else
                -- 如果父类是自定义的类,比如 A = {}
                cls.__supers = cls.__supers or {}
                cls.__supers[#cls.__supers + 1] = super       -- 保存cls的多个父类的table表
                if not cls.super then
                    -- 将遍历到的第一个table作为cls的父类
                    cls.super = super
                end
            end
        else
            -- 如果父类既不是table,也不是function的话,报错。如果父类不存在,不会执行这个循环的,所以super可以为nil。
            error(string.format("class() - create class "%s" with invalid super type",classname),0)
        end
    end
    -- 前面一大段是找到cls的所有父类;
    -- 接下来就是设置cls的元表了。
    -- 设置cls的第一索引对象是自己,如果实例对象找不到某个参数的话,
    --就会查找该类是否包含该参数,如果该类也不包含的话,就去父类查找
    cls.__index = cls   
    if not cls.__supers or #cls.__supers == 1 then  
        -- 如果cls只有一个父类,即单继承的话,设置cls的父类是他的元表
        setmetatable(cls,{__index = cls.super})
    else
        -- 如果cls是多重继承的话,__index为一个函数,找元素的时候就会执行一遍该函数
        setmetatable(cls,{__index = function(_,key)
            -- 遍历所有父类,查找key对应的值并返回
            local supers = cls.__supers
            for i = 1,#supers do
                local super = supers[i]
                if super[key] then return super[key] end
            end
        end})
    end

    if not cls.ctor then
        -- 增加一个默认的构造函数
        cls.ctor = function() end
    end
    cls.new = function(...)  -- 新建方法,这个也是比较重要的方法
        local instance
        if cls.__create then
            -- 如果有create方法,那么就调用,正常情况下,自定义的cls是没有create方法的。
            -- 通过__index和元表的index,一级一级往上找,直到找到原生cocos类
            instance = cls.__create(...)
        else
            instance = {}  -- 没有create方法,他是一个普通类
        end
        -- 设置instance的元表index,谁调用了new,就将他设置为instance的元类index
        setmetatableindex(instance,cls)
        instance.class = cls
        instance:ctor(...) --调用构造方法
        return instance
    end
    cls.create = function(_,...)
        return cls.new(...)
    end

    return cls
end

setmetatableindex = function(t,index)
    if type(t) == "userdata" then
        local peer = tolua.getpeer(t)
        if not peer then
            peer = {}
            tolua.setpeer(t,peer)
        end
        setmetatableindex(peer,index)
    else
        local mt = getmetatable(t)
        if not mt then mt = {} end
        if not mt.__index then
            mt.__index = index
            setmetatable(t,mt)
        elseif mt.__index ~= index then
            setmetatableindex(mt,index)
        end
    end
end

通过上面的class我们可以实现类的继承,如何调用呢,看下面的例子:
为了说明事例,将上面代码改造一下。

setmetatableindex = function(t,index)

    local mt = getmetatable(t)
    if not mt then
        mt = {} 
        print("setmetatableindex0001")

    end
    if not mt.__index then
        mt.__index = index
        setmetatable(t,mt)
        print("setmetatableindex0002")

    elseif mt.__index ~= index then
        print("setmetatableindex0003")
        setmetatableindex(mt,index)
    end
end

function class(classname,...)
    local cls = {__cname = classname}

    local supers = {...}   
    for _,super in ipairs(supers) do 
        local superType = type(super)

        if superType == "function" then
            print("super type is function")
            cls.__create = super
        elseif superType == "table" then
            if super[".isclass"] then
                print("super is native class")

                cls.__create = function() return super:create() end
            else
               print("super is pure lua class")

                cls.__supers = cls.__supers or {}
                cls.__supers[#cls.__supers + 1] = super     
                if not cls.super then
                    cls.super = super
                end
            end
        end
    end

    cls.__index = cls   
    if not cls.__supers or #cls.__supers == 1 then  
        print("single inherit")
        setmetatable(cls,{__index = cls.super})
    else
        print("multi inherit")
        setmetatable(cls,key)

            local supers = cls.__supers
            for i = 1,#supers do
                local super = supers[i]
                if super[key] then return super[key] end
            end
        end})
    end

    if not cls.ctor then
        cls.ctor = function() end
    end
    cls.new = function(...) 

        print("走一遍")
        local instance
        if cls.__create then
            print("had create func")
            instance = cls.__create(...)
        else
            print("no create func")
            instance = {}  
        end
        setmetatableindex(instance,cls)
        instance.class = cls
        instance:ctor(...) 
        return instance
    end
    cls.create = function(_,...)
        return cls.new(...)
    end

    return cls
end

调用:写一个Sprite.lua类

require("class")
-- 第一个类,模仿cocos的Sprite类

local Sprite = {}

Sprite.type = "Sprite"
Sprite.mark1 = 111
Sprite[".isclass"] = true
function Sprite:create( o )
    o = o or {}
    setmetatable(o,self)
    self.__index = self
    return o
end

-- 第二个类,这里他继承了Sprite类

GameSprite = class("GameSprite",-- function ()
    -- return Sprite:create()
    -- end
    Sprite
)
GameSprite.type = "GameSprite"
GameSprite.mark2 = 222

-- 第三个类,这里继承GameSprite类
testClass = class("testClass",-- function()
    -- local s = GameSprite.create()
    -- print("s.type:" .. s.type)
    -- return s
    -- end
    GameSprite
)
testClass.type = "testClass"
testClass.mark3 = 333

-- 实例化一个testclass类的对象
local test = testClass:new()

print(test.mark1)
print(test.mark2)
print(test.mark3)

输出:

super is native class
single inherit
super is pure lua class
single inherit
走一遍
had create func
setmetatableindex0003
setmetatableindex0001
setmetatableindex0002
111
222
333

通过class代码,可以看到local test 返回的实际是最顶层Sprite类的一个新建对象,然后他的元表是testClass,而testClass的元表的index是GameSprite,从而可以找到mark1,mark2,mark3都能够正确找到。

下面说明一个错误:
将上面的Sprite.lua文件的第三个类testClass的继承使用如下方法:

···
testClass = class("testClass",function()
        local s = GameSprite.create()
        print("s.type:" .. s.type)
        return s
    end
    -- GameSprite
)
···

再次运行,输出结果是:

super is native class
single inherit
super type is function
single inherit
走一遍
had create func
走一遍
had create func
setmetatableindex0003
setmetatableindex0001
setmetatableindex0002
s.type:Sprite
setmetatableindex0003
setmetatableindex0003
setmetatableindex0001
setmetatableindex0002
111
222
nil

从结果可以知道,test本身的属性mark3并没有取出来,是一个空值,Why! ! !
输出显示,我们调用了两次new方法,结果变成了:Sprite的对象的元表的index成了
GameSprite,而GameSprite的元表的元表成了testClass,而不是元表的index是testClass,也就是说Sprite对象无法找到mark3,然后去GameClass中查找,也没有查找到,又去GameClass的元表的index中茶盅,但是GameSprite的元表的index不是testClass,所以无法找到。
所以使用官方的class注意一下问题:
如果新建的类是直接继承cocos系列的类,可以直接写类名或者是使用返回create函数的方法;
但是继承的是自定义的类,那么还是使用直接谢类名,如果写函数的话,可能出现奇怪的错误。

以下是修改:
将class中的setmetatableindex函数修改成以下:

setmetatableindex = function(t,index)
    local mt = getmetatable(t)
    if not mt then
        mt = {} 
        print("setmetatableindex0001")
    end
    if not mt.__index then
        mt.__index = index
        setmetatable(t,mt)
        print("setmetatableindex0002")
    elseif mt.__index ~= index then
        print("setmetatableindex0003")
        -- 修改这个地方,将mt修改成mt.__index
        setmetatableindex(mt.__index,index)
    end
end

就能解决上面产生的问题。不行试一下咯。

由于自己是cocos2dx新手,所以该博客内容也是来自于http://www.cnblogs.com/xiaonanxia/p/4971356.html 欢迎去看原博客。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读