天天看点

quick-cocos2dx 组件管理器

接触过unity3D的都知道,unity里的对象,都是由一个空的gameObject附加上相应的组件构成的。quick-lua里也有这种功能。它是由Registry.lua,GameObject.lua和Component.lua协调完成的。如果想使用这套机制,只需要调一个函数:GameObject.extend(obj),这样obj就能附加组件了。如果相用自定义组件,则要自定义Component的派生类

-- 定义Registry类,此类用于管理所有组件类。相当于一张注册表,所有的组件都要在这张表中注册。(当然
-- 不用去显示地注册,newObject会根据组件的名字,自动加载并注册组件
local Registry = class("Registry")

Registry.classes_ = {}

-- 注册组件,这里的组件实际上就是一个类,且要派生自Component。
function Registry.add(cls, name)
    assert(type(cls) == "table" and cls.__cname ~= nil, "Registry.add() - invalid class")
    if not name then name = cls.__cname end
    assert(Registry.classes_[name] == nil, "Registry.add() - class \"%s\" already exists", tostring(name))
    Registry.classes_[name] = cls
end

-- 删除组件
function Registry.remove(name)
    assert(Registry.classes_[name] ~= nil, "Registry.remove() - class \"%s\" not found", name)
    Registry.classes_[name] = nil
end

-- 实例化指定组件,并返回该实例化对象。若指定组件还未加载,则自动加载它。
function Registry.newObject(name)
    local cls = Registry.classes_[name]
    if not cls then
        -- auto load
        pcall(function()
            cls = require(name)
            Registry.add(cls, name)
        end)
    end
    assert(cls ~= nil, string.format("Registry.newObject() - invalid class \"%s\"", tostring(name)))
    return cls.new()
end

return Registry
           
local Registry = import(".Registry")

-- 负责为target对象拓展功能,使其能够附加各种组件
local GameObject = {}

function GameObject.extend(target)
    target.components_ = {}

    function target:checkComponent(name)
        return self.components_[name] ~= nil
    end

    function target:addComponent(name)
        local component = Registry.newObject(name)
        self.components_[name] = component
        component:bind_(self)
        return component
    end

    function target:removeComponent(name)
        local component = self.components_[name]
        if component then component:unbind_() end
        self.components_[name] = nil
    end

    function target:getComponent(name)
        return self.components_[name]
    end

    return target
end

return GameObject
           
-- 组件基类,所有组件都要派生自它
local Component = class("Component")

-- 构造函数, 
-- name为组件名称
-- depends为该组件需要依赖于哪些组件,
-- 当某对象附加该组件时,会自动为且附加所有的depends组件
function Component:ctor(name, depends)
    self.name_ = name
    self.depends_ = totable(depends)
end

function Component:getName()
    return self.name_
end

-- 获取所有的依赖组件(它是一个table)
function Component:getDepends()
    return self.depends_
end

-- 获取该组件被附加到哪个组件上
function Component:getTarget()
    return self.target_
end

-- 将该组件某些的方法导出到target上
-- methods为字符串数组,字符串名字就是函数名。
-- 有了这套机制,在调用addcomponent后接着调用此函数,
-- 则以后想使用该组件的功能,直接通过target就能调用,无需先获取组件,再调用函数
function Component:exportMethods_(methods)
    self.exportedMethods_ = methods
    local target = self.target_
    local name = self.name_
    local com = self
    for _, key in ipairs(methods) do
        if not target[key] then
            target[key] = function(__, ...)
                local r = {com[key](self, ...)}
                if r[1] == self then r[1] = target end
                return unpack(r)
            end
        end
    end
    return self
end

-- 将该组件绑到target对象上
function Component:bind_(target)
    self.target_ = target
    for _, name in ipairs(self.depends_) do
        if not target:checkComponent(name) then
            target:addComponent(name)
        end
    end
    self:onBind_(target)
end

-- 解绑该组件
function Component:unbind_()
    if self.exportedMethods_ then
        local target = self.target_
        for _, key in ipairs(self.exportedMethods_) do
            target[key] = nil
        end
    end
    self:onUnbind_()
end

function Component:onBind_()
end

function Component:onUnbind_()
end

return Component