【cocos2d-x3.2游戏开发】 lua 类, 继承, 面向对象

本文转载自http://blog.csdn.net/teng_ontheway/article/details/38900211


1.lua中的类

lua中其实是没有类的,有的只是表(table),而类之间的继承也就是将父类的表连到了一起,派生类中没有找到的属性和方法就通过元表查找父类

2.lua中类的属性

classA = {width =10,height=10}

classA={}

classA.width=10

classA.height=10

两种方法都可以,通过点self.width统一调用

3.类方法


[cpp]view plaincopy

  1. functionBox:collsion()

  2. --默认第一个参数隐藏传递self,可以通过self.xxx调用属性和方法

  3. end

  4. functionBox.create(self)

  5. --必须手动传递参数self,否则无法用self.xxx调用属性和方法

  6. end

函数的声明和调用可以用":"和".",属性调用全部用点"."


4.类与元表的用法

lua查找一个表元素时的规则,其实就是如下3个步骤:

4.1.在表中查找,如果找到,返回该元素,找不到则继续

4.2.判断该表是否有元表,如果没有元表,返回nil,有元表则继续

4.3.判断元表有没有__index方法,如果__index方法为nil,则返回nil;如果__index方法是一个表,则重复1、2、3;如果__index方法是一个函数,则返回该函数的返回值

例如:

  • father={

  • house=1

  • }

  • son={

  • car=1

  • }

  • setmetatable(son,father)--把son的metatable设置为father

  • print(son.house)

  • 输出结果是nil,如果代码改为

  • father={

  • house=1

  • }

  • father.__index=father--把father的__index方法指向自己

  • son={

  • car=1

  • }

  • setmetatable(son,father)

  • print(son.house)

  • 输出的结果就为1了

    这就解释了为什么我们经常在cocos2dx的类中经常见到如下

  • localBox=class("Box",function(filename)

  • returncc.Sprite:create(filename)

  • end)

  • Box.__index=Box

  • 设置Box的元表的__index方法为自己,当派生类"SmallBox"派生自"Box",如果在SmallBox中查找不到的属性和方法,就检索元表,当然不是直接从元表中直接检索,是检索元表下的__index,如果__index为nil,则返回nil,如果__index是一个表,那么就到__index方法所指的表中查找对应的属性和方法

    具体可以参考:Lua查找表元素过程(元表、__index方法是如何工作的)

    5.Cocos2dx中的类

    lua没有面向对象一说,cocos为我们准备了class的lua端函数,我们参考quick的class函数,里面还有对应的例子

  • --[[--

  • 创建一个类

  • ~~~lua

  • --定义名为Shape的基础类

  • localShape=class("Shape")

  • --ctor()是类的构造函数,在调用Shape.new()创建Shape对象实例时会自动执行

  • functionShape:ctor(shapeName)

  • self.shapeName=shapeName

  • printf("Shape:ctor(%s)",self.shapeName)

  • end

  • --为Shape定义个名为draw()的方法

  • functionShape:draw()

  • printf("draw%s",self.shapeName)

  • end

  • --

  • --Circle是Shape的继承类

  • localCircle=class("Circle",Shape)

  • functionCircle:ctor()

  • --如果继承类覆盖了ctor()构造函数,那么必须手动调用父类构造函数

  • --类名.super可以访问指定类的父类

  • Circle.super.ctor(self,"circle")

  • self.radius=100

  • end

  • functionCircle:setRadius(radius)

  • self.radius=radius

  • end

  • --覆盖父类的同名方法

  • functionCircle:draw()

  • printf("draw%s,raidus=%0.2f",self.shapeName,self.raidus)

  • end

  • --

  • localRectangle=class("Rectangle",Shape)

  • functionRectangle:ctor()

  • Rectangle.super.ctor(self,"rectangle")

  • end

  • --

  • localcircle=Circle.new()--输出:Shape:ctor(circle)

  • circle:setRaidus(200)

  • circle:draw()--输出:drawcircle,radius=200.00

  • localrectangle=Rectangle.new()--输出:Shape:ctor(rectangle)

  • rectangle:draw()--输出:drawrectangle

  • ~~~

  • ###高级用法

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

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

  • ~~~lua

  • --从cc.Node对象派生Toolbar类,该类具有cc.Node的所有属性和行为

  • localToolbar=class("Toolbar",function()

  • returndisplay.newNode()--返回一个cc.Node对象

  • end)

  • --构造函数

  • functionToolbar:ctor()

  • self.buttons={}--用一个table来记录所有的按钮

  • end

  • --添加一个按钮,并且自动设置按钮位置

  • functionToolbar:addButton(button)

  • --将按钮对象加入table

  • self.buttons[#self.buttons+1]=button

  • --添加按钮对象到cc.Node中,以便显示该按钮

  • --因为Toolbar是从cc.Node继承的,所以可以使用addChild()方法

  • self:addChild(button)

  • --按照按钮数量,调整所有按钮的位置

  • localx=0

  • for_,buttoninipairs(self.buttons)do

  • button:setPosition(x,0)

  • --依次排列按钮,每个按钮之间间隔10点

  • x=x+button:getContentSize().width+10

  • end

  • end

  • ~~~

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

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

  • ~~~lua

  • functionToolbar:setPosition(x,y)

  • --由于在Toolbar继承类中覆盖了cc.Node对象的setPosition()方法

  • --所以我们要用以下形式才能调用到cc.Node原本的setPosition()方法

  • getmetatable(self).setPosition(self,x,y)

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

  • end

  • ~~~

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

  • @paramstringclassname类名

  • @param[mixedsuper]父类或者创建对象实例的函数

  • @returntable

  • ]]

  • functionclass(classname,super)

  • localsuperType=type(super)

  • localcls

  • ifsuperType~="function"andsuperType~="table"then

  • superType=nil

  • super=nil

  • end

  • ifsuperType=="function"or(superandsuper.__ctype==1)then

  • --inheritedfromnativeC++Object

  • cls={}

  • ifsuperType=="table"then

  • --copyfieldsfromsuper

  • fork,vinpairs(super)docls[k]=vend

  • cls.__create=super.__create

  • cls.super=super

  • else

  • cls.__create=super

  • cls.ctor=function()end

  • end

  • cls.__cname=classname

  • cls.__ctype=1

  • functioncls.new(...)

  • localinstance=cls.__create(...)

  • --copyfieldsfromclasstonativeobject

  • doinstance[k]=vend

  • instance.class=cls

  • instance:ctor(...)

  • returninstance

  • end

  • else

  • --inheritedfromLuaObject

  • ifsuperthen

  • cls={}

  • setmetatable(cls,{__index=super})

  • cls.super=super

  • else

  • cls={ctor=function()end}

  • end

  • cls.__cname=classname

  • cls.__ctype=2--lua

  • cls.__index=cls

  • functioncls.new(...)

  • localinstance=setmetatable({},cls)

  • instance.returninstance

  • end

  • end

  • returncls

  • end


  • 传入是一个父类的话,会调用cls.new函数,然后创建实例,调用ctor构造函数

    6. 调用一个实例:

    假设派生自一个cocos的类 Sprite

  • --class可以传1、2个参数

  • --@param类名,内部做记录而已,一般和返回的类名一致即可

  • --@param如果传参数2使用当前函数作为构造函数如果没参数2默认的构造函数

  • localBox=returncc.Sprite:create(filename)

  • end)

  • --设置元彪更改元表默认的元方法

  • --访问table中不存在的字段时,解释器查找__index的元方法,否则返回nil

  • --多用于继承http://blog.csdn.net/q277055799/article/details/8463883

  • Box.__index=Box

  • Box.isDead=false--定义属性

  • --构造函数(会自动调用)

  • --外界构造时可以传任意参数XXX.new(...)

  • functionBox:ctor(pic_path)

  • localfunctiononNodeEvent(event)

  • if"enter"==eventthen

  • Box:onEnter(pic_path)

  • elseif"exit"==eventthen

  • Box:onExit()

  • end

  • end

  • self:registerScriptHandler(onNodeEvent)

  • localfunctiononUpdate()

  • end

  • self:scheduleUpdateWithPriorityLua(onUpdate,0)

  • end

  • functionBox:onEnter(pic_path)

  • end

  • functionBox:onExit()

  • end

  • functionBox.create(parent,position)

  • localbox=Box.New("data/box.png")

  • parent:addChild(box)

  • returnbox

  • end

  • returnBox


  • 如果是一个table,可以直接使用

  • localBomb=class("Bomb")


  • 7.我们常见cocos2dx的例子中有大量的extend和tolua.getpeer用法如下:

  • localTimelineTestScene=class("TimelineTestScene")

  • TimelineTestScene.__index=TimelineTestScene

  • functionTimelineTestScene.extend(target)

  • localt=tolua.getpeer(target)

  • ifnottthen

  • t={}

  • tolua.setpeer(target,t)

  • end

  • setmetatable(t,TimelineTestScene)

  • returntarget

  • end

  • functionTimelineTestScene.create()

  • localscene=TimelineTestScene.extend(cc.Scene:create())

  • returnscene

  • end

  • 用的时tolua.getpeer,其实它的功能就相当于调用了class,所以请远离extend吧

    class("TimelineTestScene",cc.Scene)

  • TimelineTestScene.__index=TimelineTestScene

  • 相关文章

        本文实践自 RayWenderlich、Ali Hafizji 的文章《...
    Cocos-code-ide使用入门学习地点:杭州滨江邮箱:appdevzw@1...
    第一次開始用手游引擎挺激动!!!进入正题。下载资源1:从C...
        Cocos2d-x是一款强大的基于OpenGLES的跨平台游戏开发...
    1.  来源 QuickV3sample项目中的2048样例游戏,以及最近《...
       Cocos2d-x3.x已经支持使用CMake来进行构建了,这里尝试...