接触过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