Cocos2dx-lua -- 入门-class
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都能够正确找到。 下面说明一个错误: ···
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! ! ! 以下是修改: 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 欢迎去看原博客。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |