cocos2d开发学习三:节点的动作(Action)介绍
一:动作Actions
从上一篇我们看到菜单场景中菜单layer加载进来有个从上滑入的动作效果
[cpp]
//动作1
id ac = [CCMoveTo actionWithDuration:2 position:CGPointMake(winSize.width/2, winSize.height/2)];
CCRepeat *repe = [CCRepeat actionWithAction:ac times:4];
//动作二
id bc = [CCCallFunc actionWithTarget:self selector:@selector(test)];
CCSequence *seq = [CCSequence actions:repe,bc,nil];
[menu runAction:seq];
上面只是一个很简单的例子,用cocos2d的ccAction类来实现节点元素的一些动作。
比如移动,旋转等。
因为我们知道,cocos2d中scene,layer,sprite都实现了CCNode这个基类,
也就是说其实动作这个运用范围不是我们一般狭隘的以为只是运用在Sprites上。
在layer,scene什么的都是可以运用其中,当然,最多的还是运用在精灵上。
比如我们控制人物精灵的走动跳跃等等。
cocos2D广义上将动作分为“即时动作”和“延时动作”。
即时动作更像是如设定对象的属性一样。
而延时动作也就是我们上面用到移动就是一种。
物体运动什么的都属于这个范畴。
延时动作:
1.常见的延时动作:CCMoveTo移动到,CCJumpTo跳跃到,方法都会接受不同参数,
但是我们延时动作至少要接受延时时间的参数。
2.舒缓动作CCEaseAction,
说白了我们简单就是让动作有个循序渐进的缓冲,
在视觉上更具美感。
很多时候,这个类额应用其实就是对上面的基本延时动作做了一层装饰。
[java]
<strong> CCAction *c = [CCMoveTo actionWithDuration:5 position:ccp(240, 160)];
CCEaseInOut *ci = [CCEaseInOut actionWithAction:c rate:5];
[self runAction:ci];
</strong>
如上面这段代码,我有一个移动的动作,然后装饰成移动开始时和结束时速度渐变效果。
常见的舒缓动作类
1. CCEaseBackIn, CCEaseBackInOut, CCEaseBackOut2. CCEaseBounceIn, CCEaseBounceInOut, CCEaseBounceOut
3. CCEaseElasticIn, CCEaseElasticInOut, CCEaseElasticOut
4. CCEaseExponentialIn, CCEaseExponentialInOut, CCEaseExponentialOut
5. CCEaseIn, CCEaseInOut, CCEaseOut
6. CCEaseSineIn, CCEaseSineInOut, CCEaseSineOut
重复动作:
重复动作从字面看其实很好理解。
但是真正用起来具有局限性。比如我下面这段代码
[cpp]
CCAction *c = [CCMoveTo actionWithDuration:3 position:ccp(20, 100)];
CCEaseInOut *ci = [CCEaseInOut actionWithAction:c rate:5];
CCRepeat *re = [CCRepeat actionWithAction:ci times:2];
[self runAction:re];
是没有重复效果的,而不是我们以为的如Android中类似是有我们这样思路的动作效果。
动作最后还是只是执行了一次。
后来我大致这么猜测
重复动作其实可以看成就是一个动作序列(对于于动作序列下面马上提到),重复N次就是添加了N个这样的Action。 www.zzzyk.com
但是为什么我们肉眼只能看到移动动作只执行了一次。
其实这是我们自己造成的错误思维,
在我们思维中,以为比如重复2次这个moveto动作,第一次移动完了后,我们看到的现象是这个物体又突然出现在原来开始点,然后再次发生移动。
但是其实moveTo函数中我们传递一个postion,也就是移动到屏幕的位置p,第二次要在重复时,因为移动动作的起始位置就是要移动的左边p。
因此看上去是不动的(好吧,上面只是自己的自我解释而已~)
但是用CCMoveBy的话是可以的,因为传入的参数是个偏移值。
可是在在部分网上资料上说:
这里需要注意的是actionBy不能重复使用,如果第二次使用的话,会继续从第一次使用到的位置开始继续,不明白的可以尝试一下,现象很明显!
所以说其的局限性么,当然,api'也不过是提出这么一个概念罢了。
[cpp]
CCRotateBy* rotateBy = [CCRotateBy actionWithDuration:2 angle:360];
CCRepeatForever* repeat = [CCRepeatForever actionWithAction:rotateBy];
[myNode runAction:repeat];
这个是资料上提供的一个列子。
动作序列
CCSequence *seq = [CCSequence actions:repe,bc,nil];
[menu runAction:seq];
顾名思义,一个动作接一个动作。
本身也是继承了action类。
说道连续动作顺便提下上面我们即时动作
我们说了,即时动作更像是一直属性设置。但是cocos2d为什么还要引入即时动作这个概念呢。
其实就是为了配合动作序列来说,就觉得,这个设计逻辑的好处了。
举例:一个物体先移动到p,然后突然消失(hide),然后又移动到q,然后突然出现。
从这段描述,我们可以这么设计,先是一个延时动作A,然后突然消失,那设置属性呗(object.hide),然后在延时动做B,然后再设置属性show。
好了,这边我们就会发现一个问题,如果是是以上面额思维来设计,A动作finish后可能需要一个回调来执行属性,也有人说,把属性设置也当成一个动作,
放在队列里啊。然后问题就出在这里了,我这个设置属性的动作以什么形式放进去,即时动作其实就是这么一个让序列看起统一的设计。
对于即时动作,资料上也说了:你可能会奇怪为什么有基于CCInstantAction的即时动作存在,通过改变节点的 属性不是可以达到一样的目的吗?比如那些用来翻转节点,把节点放置的指定 的地方,还有用于开关节点的可视性属性的即时动作。
但是通过上面的延时动作,做过android的就会有种不习惯,我第一个动作执行完后在执行第二个前要做一些额外操作,然后貌似它没有类似于android中监听这么一种概念机制。
初看即时动作中最常用的CCCallFunc动作的调用格式,就会发现不正是一种回调么。
而Android的回调执行一般是在前一个动作的finish方法里,但是对于ios,因为放入了序列里,
然后起一个动作执行玩了来执行下一个动作。这个动作是我们自定义的一个操作函数而已。
而非实际意义上必须产生物体移动的才叫动作。动作队列最后也不过是成了一个操作队列。
因此,即时动作的作用也就不言而喻了,在一个动作序列中配合使用,可以让动作更加灵活。
[cpp]
CCCallFunc* func = [CCCallFunc actionWithTarget:self selector:@selector(onCallFunc)]; CCCallFuncN* funcN = [CCCallFuncN actionWithTarget:self selector:@selector(onCallFuncN:)];
CCCallFuncND* funcND = [CCCallFuncND actionWithTarget:self selector:@selector(onCallFuncND:data:) data:(void*)self];
CCSequence* seq = [CCSequence actions:tint1, func, tint2, funcN, tint3, funcND, nil]; [label runAction:seq];
同步操作
CCSpawn,这个就没什么说的,相信做个一些动画效果的都知道比如一个圆一边颜色渐变,一边从小变大。
只不过要明白点,同步执行最后的完成时间由基本动作中用时最大者决定。
作者:Nono_Love_Lilith
补充:移动开发 , 其他 ,