探讨一下行为类。
从代码的角度讲,行为其实就是改变实体的属性,如坐标、角度等,这些属性大部分都可以靠实体类自身封装的方法来设置,之所以要用行为单独封装它们,还是为了使操作更加简便。试想,当我们要让一个实体连续执行一段行为序列或者不断重复执行一个行为时,编码会变得相当复杂,如果这一过程还是在一定时间内逐渐完成的该怎么办,各种复杂的行为掺杂在一起同时执行,是不是想一想就头大呢?这就是行为类存在的最大意义,它会使编码过程变得异常简单,就像是策划在写脚本一样~
行为类的基类是CCAction,任何一种行为都是由它拓展衍变而来的。行为类可以分为四大类:有限次执行类、无限重复行为类、速度行为类和跟随移动类,其中前两者的使用频率最高;而有限次执行类又可以分为瞬时行为类和过程行为类。它们的继承关系如下图:
图中的CCAction是基类,比较抽象,在实际开发中不会直接用到,更多的是在参数传递中充当‘泛型’;CCFiniteTimeAction从字面就能看出来(finite = 有限的),是有限次执行类,它是最为普通的行为,就是按时间顺序做一系列事情,做完后行为结束;CCRepeatForever的名字更易懂了,无限重复行为类,就是说它可以让节点反复的做一件事,除非把行为或节点删除,否则永远不会停止;CCSpeed的作用是调整行为实例的执行速度,因此它依赖于其它的行为,单独的CCSpeed没有意义;CCFollow可以使节点跟随指定的另一个节点移动。
下面我就介绍一下这些类的工作原理:
CCAction声明了如下方法:
+(id) action
创建一个CCAction实例,其实就是封装了alloc、init和autorelease方法。
-(void) startWithTagert: (id)aTarget
将节点与行为对象相关联。
-(void) stop
取消节点与行为的关联,即停止行为。
-(void) isDone
检测行为是否执行完毕。
-(void) step
计算自身行为的执行状况,即任务完成了多少,并调用自身的update。
-(void) update
执行自身行为的主逻辑,是行为的核心算法。
-(void) pause
暂停行为(可恢复)。
-(void) unPause
从暂停中恢复。
-(BOOL) isRunning
检测行为是否在更新逻辑。
*需要注意的是,CCAction是抽象类,很多方法都是空的,它主要靠自己的子类去实现接口,因此不能直接用CAction的对象描述节点的行为。
CCFiniteTimeAction
CCFiniteTimeAction是所有有限次执行类(或者也可以叫顺序执行类吧)的基类,这种类在游戏中的应用是相当多的,因此尽管它也是个抽象类,但对于它的理解将直接影响到游戏开发的效率与质量。
-( CCFiniteTimeAction*) reverse
CCFiniteTimeAction只增加了一个接口,其作用是反向执行一个行为,比如一个行为对象的作用是将节点右移10个像素,那么当这个对象执行了reverse后,执行它的节点会向左移动10像素。但是CCFiniteTimeAction只是声明了该方法,实现还是交给了它的子类。
CCRepeatForever
CCRepeatForever的接口和CCFiniteTimeAction大致相同(除了初始化),只是实现方法不同。它们的区别是:CCFiniteTimeAction执行有限次,有结束的一刻,而CCRepeatForever永远不会自己停止,会无限的执行;CCFiniteTimeAction的子类有具体的行为含义,可以独立存在,而CCRepeatForever没有具体含义,它只表示会重复地执行,因此它必须依附于有具体含义的行为。
+(id) actionWithAction: (CCActionInterval*)action
CCRepeatForever其实是对另一个行为的封装,参数action就是被封装的行为对象。
CCSpeed
CCSpeed的接口和CCRepeatForever一样,没有什么特别之处,它的作用就是改变其它行为的执行速度,比如一个精灵以每秒10帧的速度切换自己的frame来播放动画,CCSpeed可以将其改成每秒20帧或每秒5帧。
CCFollow
+(id) actionWithTarget: (CCNode*)fNode
使节点跟随另一个节点移动,参数fNode即为被跟随的节点。
+(id) actionWithTarget: (CCNode*)fNode worldBoundary: (CGRect)rect
使节点跟随另一个节点移动,参数rect表示跟随者只能在该区域内移动,如超出该范围,则停止跟随。
CCActionInterval
持续性(防和谐= =)行为类,CCFiniteTimeAction的子类,因此能和所有继承自CCFiniteTimeAction的类的对象组成行为序列,换句话说,它不能和CCRepeatForever、CCSpeed以及CCFollow组成行为序列。它和CCActionInstant的区别在于:CCActionInterval行为的执行需要一定的时间(或者说一个过程),而CCActionInstant的行为都是瞬间完成的,没有过程(类似节点的各种“set”方法)。
+(id) actionWithDuration: (ccTime)d
持续行为类的标志性方法,作用为创建一个在d秒内执行完自身行为的对象并返回。
-(id) initWithDuration: (ccTime)d
初始化,将设置行为的执行时间设置为d秒。
CCActionInstant
瞬时行为类,CCFiniteTimeAction的子类,能和所有继承自CCFiniteTimeAction的类的对象组成行为序列。它与CCActionInterval的唯一区别就是没有执行过程。CCActionInstant的接口没有什么特别之处,就不单独介绍了。
下面列出的是瞬时行为类的子类
CCHide 隐藏节点,效果类似于CCNode的setVisible:No ,将其封装成action是为了使其可以和其他行为组成一个连续的行为序列。
[CCHide action]
CCShow 显示节点,效果类似于CCNode的setVisible:Yes ,与CCHide的作用正好相反。
[CCShow action]
CCToggleVisibility 切换节点可见性,即当节点可见时设为不可见,不可见时设为可见。
[CCToggleVisibility action]
CCPlace 放置节点,效果类似于CCNode的setPosition。
[CCPlace actionWithPosition:pos]
CCFlipX 横向翻转节点,效果等同于CCNode执行setFlipX函数。
[CCFlipX actionWithFlipX:isFlip]
CCFlipY 纵向翻转节点,效果等同于CCNode执行setFlipY函数。
[CCFlipY actionWithFlipYX:isFlip]
CCCallFunc 自定义行为,效果为调用一个自定义的方法,通过方法的实现来达到自己想要的效果。
[CCCallFunc actionWithTarget:self selector:@selector(fun)]
CCCallFuncN 自定义行为,效果与CCCallFunc基本相同,只是会将节点对象作为参数传递给被调用的函数。
[CCCallFuncN actionWithTarget:self selector:@selector(fun:)]
CCCallFuncND 自定义行为,效果与CCCallFuncN基本相同,只是可以额外传递一个参数给被调用的函数。
[CCCallFuncND actionWithTarget:self selector:@selector(fun:data:) data:object]
*需要特别注意的是,CallFunc虽然是瞬时行为,但这个“瞬时”只体现在它调用函数是在一瞬间完成的,但这个函数的执行可能需要一段时间,就是说CallFunc的行为已经做完了,开始执行序列后面的行为,但被调用的函数还没有完成,此时它们是并行的。
下面是持续行为类,它们全部继承自CCActionInterval
CCMoveTo 将节点移动到指定坐标。
[CCMoveTo actionWithDuration:time position:pos]
CCMoveBy 使节点根据参数发生相对位移。
[CCMoveBy actionWithDuration:time position:pos]
CCJumpTo 使节点跳跃到指定的位置,可以设置高度和次数。
[CCJumpTo actionWithDuration:time position:pos height:height jumps:times]
CCJumpBy 和CCJumpTo类似,但是位移是相对位移。
[CCJumpBy actionWithDuration:time position:pos height:height jumps:times]
CCBezierBy 使节点按贝塞尔曲线运动。
[CCBezierBy actionWithDuration:time Bezier:path] (path的类型是ccBezerConfig,这是一个结构体,成员见下方)
CGPoint endPosition 曲线的终点坐标(相对于起点的偏移量,非绝对坐标),图中的P3
CGPoint controlPoint_1 曲线第一个弧度的参考点坐标(相对于起点的偏移量,非绝对坐标),图中的P1
CGPoint controlPoint_2曲线第二个弧度的参考点坐标(相对于起点的偏移量,非绝对坐标),图中的P2
CCScaleTo 设置节点的缩放倍率。
[CCScaleTo actionWithDuration:time scale:rate]
[CCScaleTo actionWithDuration:time scaleX:x scaleY:y]
CCScaleBy 缩放节点(相对)
[CCScaleBy actionWithDuration:time scale:rate]
[CCScaleBy actionWithDuration:time scaleX:x scaleY:y]
CCRotateTo 设置节点的旋转角度。
[CCRotateTo actionWithDuration:time angle:rotate]
CCRotateBy 旋转节点
[CCRotateBy actionWithDuration:time angle:rotate]
CCBlink 使节点闪烁,可以设置闪烁次数。
[CCBlink actionWithDuration:time blinks:times]
CCTintTo 设置节点色调。
[CCTintTo actionWithDuration:time red:r green:g blue:b]
CCTintBy 使节点色调发生偏移。
[CCTintBy actionWithDuration:time red:r green:g blue:b]
(*颜色的参数类型其实就是无符号的byte)
CCFadeTo 逐渐改变透明度
[CCFadeTo actionWithDuration:time opacity:color]
CCFadeIn 淡入。
[CCFadeIn actionWithDuration:time]
CCFadeOut 淡出。
[CCFadeOut actionWithDuration:time]
CCDelay 延迟,即增加一个间歇时间。
[CCDelay actionWithDuration:time]
复合行为
CCSequence 行为序列(继承自CCActionInterval),即将若干个待执行的行为按顺序组合在一起,然后依次执行,如果中间有持续行为的话则等到前一个行为执行完毕后再执行下一个(CCCallFunc是并行),因此单独的CCSequence对象是没有意义的。
[CCSequence actions:act0, act1, act2, nil] (act0、act1、act2都是单独的行为对象)
[CCSequence actionsWithArray:act] (act是保存着行为对象的数组)
CCSpawn 并行行为(继承自CCActionInterval),即将若干个待执行的行为组合在一起,同时执行它们,行为的执行时间以最长的那个行为为准,就是说当全部的子行为结束时,CCSpawn才算结束。单独的CCSpawn对象也没有意义。
[CCSpawn actions:act0, act1, act2, nil]
[CCSpawn actionsWithArray:act]
CCRepeat 重复执行行为(继承自CCActionInterval),就是将一个已知的行为或行为序列多次执行,执行的次数通过参数设定,效果类似于CCRepeatForever,但CCRepeat只执行有限次,有运行结束的那一刻。
[CCRepeat actionWithAction:act times:times]
*上面的三个类都是容器,可以容纳多个行为,它们之间也可以互相容纳。
CCAnimation 动画,这个行为有点特殊,它并非继承自CCAction以及CCAction的任何子类,相对来说是个独立的行为。CCAnimation的作用是根据一个帧序列连续切换,形成一个动画,可以说是专门为精灵类准备的。
变速类行为
这类行为的作用就是改变另一行为的速度,基类是CCEaseAction,继承自CCActionInterval。
CCEaseIn 由快至慢
CCEaseOut 由慢至快
CCEaseInOut 由快至慢再由慢至快
CCEaseSineIn 由快至慢
CCEaseSineOut 由慢至快
CCEaseSineInOut 由快至慢再由慢至快
CCEaseExponentianIn 由极快至慢
CCEaseExponentianOut 由慢至极快
CCEaseExponentianInOut 由极快至慢再由慢至极快
CCActionmanager
这个类其实并不属于行为类,它的父类是NSObject,而不是CCAction,但它又与CCAction密不可分,因此在这里单独介绍下。
CCActionmanager是个标准的单例类,它的作用顾名思义,就是管理行为类的对象,工作原理是:当节点执行runAction时,会把action通过addAction方法将对象传递给CCActionmanager的单例,该实例再把这个action添加到自己的行为序列中。CCActionmanager通过schedule定时刷新自己的update方法,在这个方法中去调用行为序列中每个action的step(会有一些筛选条件,比如暂停的行为不会update),这些step方法再根据自身的完成进度去update或是结束行为。就是说实际上是由CCActionmanager驱动的每个action去更新自己的逻辑,而runAction方法只是将行为对象添加进CCActionmanager的更新队列罢了。当节点被清除或是行为结束时,CCActionmanager会自动将action从队列中剔除,无需开发者操心。
到这里行为类的工作原理已经介绍的差不多了,一些细节上的东西很难一次讲清楚,我会在后面的章节中尽量补充,大家如果觉得有欠缺的话希望能够提出来,以帮助我们改进,谢谢。
下面是代码示例(下载)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
-(id) init { self = [super init]; if (self) { //创建层,并添加为场景的子节点 m_layer = [[CCLayer alloc] init]; [self addChild:m_layer]; //根据图片yz创建精灵,精灵的使用之后会做介绍 m_actor = [CCSprite spriteWithFile:@"yz.png"]; //设置精灵的坐标点为120, 300 [m_actor setPosition:CGPointMake(120, 300)]; //设置精灵的行为 [self setAction]; //将精灵添加为层的子节点,Z轴为1,标签为1 [m_layer addChild:m_actor z:1 tag:1]; } return self; }
-(void) setAction { //向下移动120像素 id moveDown = [CCMoveBy actionWithDuration:1 position:CGPointMake(0, -120)]; //向右移动90像素 id moveRight = [CCMoveBy actionWithDuration:1 position:CGPointMake(90, 0)]; //向上移动120像素 id moveUp = [CCMoveBy actionWithDuration:1 position:CGPointMake(0, 120)]; //向左移动90像素 id moveLeft = [CCMoveBy actionWithDuration:1 position:CGPointMake(-90, 0)]; //放大1/4 id zoomOut = [CCScaleBy actionWithDuration:0.3f scale:1.25f]; //缩小20% id zoomIn = [CCScaleBy actionWithDuration:0.3f scale:0.8f]; //将下移、右移、上移、左移组成一个顺序序列 id moveSet = [CCSequence actions:moveDown, moveRight, moveUp, moveLeft, nil]; //将放大、缩小组成一个顺序序列,并重复3次 id zoomSet = [CCRepeat actionWithAction:[CCSequence actions:zoomOut, zoomIn, nil] times:3]; //将移动和缩放两个序列组合成一个并列执行的任务 id singleAct = [CCSpawn actions:moveSet, zoomSet, nil]; //无限循环这个并行的组合序列 id repeatAct = [CCRepeatForever actionWithAction:singleAct]; //启动action [m_actor runAction:repeatAct]; } |
运行后的效果(图片会以一个矩形的轨迹逆时针运动,每走一圈会缩放三次)