Cocos2d-x 之CCAction

動作是指在特定時間內完成移動、縮放、旋轉等操作的行爲,節點可以通過運行動作來實現動畫效果,這裏的動作就是指CCAction對象,它有很多的子類,每個子類都封裝了不同的動作效果。

先來看看CCAction的繼承結構圖

這裏我省略了瞬時動作(CCActionInstant)和間隔動作(CCActionInterval)的子類,因爲它們又包含了非常多的子類,待會再介紹它們的子類。

CCAction和CCFiniteTimeAction都是抽象類,只定義了一些基本屬性和方法,沒有實際用途,我們需要使用它們的子類來初始化動作,然後運行到節點上。


間隔動作

間隔動作就是指需要經過一段時間才能完成的動作,所有的間隔動作都繼承自CCActionInterval。比如CCRotateBy,可以在指定時間內旋轉指定的角度

// 1秒內順時針旋轉360°
CCRotateBy *rotate = [CCRotateBy actionWithDuration:1 angle:360];
[sprite runAction:rotate];


間隔動作的繼承結構圖:(只列出部分常用的)


由於CCActionInterval的子類太多了,這裏就不一一介紹了,可以查閱下API文檔

下面列舉一下常見的CCActionInterval的子類:

1.CCBlink

閃爍效果

// 5秒內閃爍20次
CCBlink *blink = [CCBlink actionWithDuration:5 blinks:20];
[sprite runAction:blink];

2.CCMoveBy和CCMoveTo

CCMoveBy是移動一段固定的距離,CCMoveTo是移動到指定的位置

// 在1秒內,向右移動100單位,同時向上移動80單位
CCMoveBy *moveBy = [CCMoveBy actionWithDuration:1 position:CGPointMake(100, 80)];

// 在1秒內,從節點的當前位置移動到(100, 80)這個位置
CCMoveTo *moveTo = [CCMoveTo actionWithDuration:1 position:CGPointMake(100, 80)];

3.CCRotateBy和CCRotateTo

CCRotateBy是在當前旋轉角度的基礎上再旋轉固定的角度,CCRotateTo是從當前旋轉角度旋轉到指定的角度

假設精靈在初始化的時候已經順時針旋轉了45°

sprite.rotation = 45;


如果使用了CCRotateBy

CCRotateBy *rotateBy = [CCRotateBy actionWithDuration:1 angle:90];
[sprite runAction:rotateBy];

// 在1秒內,再順時針旋轉90°,那麼sprite的最終旋轉角度是45° + 90° = 135°

如果使用了CCRotateTo
CCRotateTo *rotateTo = [CCRotateTo actionWithDuration:1 angle:90];
[sprite runAction:rotateTo];

// 在1秒內,順時針旋轉到90°,sprite的最終旋轉角度就是90°

4.CCScaleBy和CCScaleTo

CCScaleBy是在當前縮放比例的基礎上再縮放固定的比例,CCScaleTo是從當前縮放比例縮放到指定的比例

假設精靈在初始化的時候的縮放比例爲0.8

sprite.scale = 0.8;

如果使用了CCScaleBy
CCScaleBy *scaleBy = [CCScaleBy actionWithDuration:1 scale:0.5];
[sprite runAction:scaleBy];
// 在1秒內,寬度和高度再縮小50%,那麼sprite最終縮放比例是0.8 * 0.5 = 0.4

如果使用了CCScaleTo

CCScaleTo *scaleTo = [CCScaleTo actionWithDuration:1 scale:0.5];
[sprite runAction:scaleTo];
// 在1秒內,寬度和高度縮小爲0.5倍,那麼sprite最終縮放比例是就0.5

5.CCFadeIn和CCFadeOut和CCFadeTo

CCFadeIn是淡入,即由暗轉亮,從沒有到有;CCFadeOut是淡出,即由亮轉暗,從有到沒有;CCFadeTo用來修改節點的不透明度

// 在2秒內,從沒有到有
CCFadeIn *fadeIn = [CCFadeIn actionWithDuration:2];

// 在2s內,從有到沒有
CCFadeOut *fadeOut = [CCFadeOut actionWithDuration:2];

// 在2s內,不透明度變爲120,即變爲半透明 (不透明度取值範圍是0-255)
CCFadeTo *fadeTo = [CCFadeTo actionWithDuration:2 opacity:120];


6.CCRepeat

重複執行某個動作,可以指定重複的次數

// 1秒中順時針旋轉360°
CCRotateBy *rotateBy = [CCRotateBy actionWithDuration:1 angle:360];
// 重複執行2次旋轉動畫
CCRepeat *repeat = [CCRepeat actionWithAction:rotateBy times:2];

[sprite runAction:repeat];

7.CCAnimate

按順序地播放圖片,可以實現幀動畫。

例如有下面10張圖片:(玩過街機的同學應該很熟悉,趙雲的大鵬展翅)

不難發現,如果從1.png 到 10.png按順序顯示圖片的話會形成一個動畫

下面用CCAnimate實現動畫效果

// 用來存放所有的幀
NSMutableArray *frames = [NSMutableArray array];
// 加載所有的圖片
for (int i = 1; i<= 10; i++) {
    // 文件名
    NSString *name = [NSString stringWithFormat:@"zy.bundle/%i.png", i];
    // 根據圖片名加載紋理,一個圖片對應一個紋理對象
    CCTexture2D *texture = [[CCTextureCache sharedTextureCache] addImage:name];
    // 根據紋理初始化一個幀
    CGRect retct = CGRectMake(0, 0, texture.contentSize.width, texture.contentSize.height);
    CCSpriteFrame *frame = [[[CCSpriteFrame alloc] initWithTexture:texture rect:retct] autorelease];
    // 添加幀到數組中
    [frames addObject:frame];
}

// 根據幀數組初始化CCAnimation,每隔0.1秒播放下一張圖片
CCAnimation *animation = [CCAnimation animationWithFrames:frames delay:0.1];

// 根據CCAnimation對象初始化動作
CCAnimate *animate = [CCAnimate actionWithAnimation:animation];

[sprite runAction:animate];
動畫效果如下:

裏是將10幀分爲10張不同的png圖片。爲了性能着想,其實最好將10幀打包成一個圖片,到時從這張圖片上面切割每一幀,這種圖片我們可以稱爲"紋理相冊",可以用TexturePacker製作紋理相冊


8.CCSequence

一般情況下,如果給節點同時添加幾個動作時,它們會同時運行。比如下面的代碼效果是一邊旋轉一邊縮放

CCRotateBy *rotateBy = [CCRotateBy actionWithDuration:1 angle:360];
CCScaleBy *scaleBy = [CCScaleBy actionWithDuration:1 scale:2];

[sprite runAction:rotateBy];
[sprite runAction:scaleBy];
但是有時候我們想讓動作一個接着一個運行,那麼就要用到CCSequence
下面演示的效果是,讓精靈先變爲紅色,再從紅色變爲綠色,再從綠色變爲藍色

CCTintTo *tintTo1 = [CCTintTo actionWithDuration:1 red:255 green:0 blue:0];
CCTintTo *tintTo2 = [CCTintTo actionWithDuration:1 red:0 green:255 blue:0];
CCTintTo *tintTo3 = [CCTintTo actionWithDuration:1 red:0 green:0 blue:255];
// CCTintTo也是CCActionInterval的子類,可以用於更改精靈的顏色。

CCSequence *sequence = [CCSequence actions:tintTo1, tintTo2, tintTo3, nil];
[sprite runAction:sequence];
CCSequence會按順序執行參數中傳入的所有動作


9.CCActionEase

當對節點使用CCMoveTo動作時,它會勻速移動到目的地,如果使用CCActionEase就可以使節點由慢到快或者由快到慢地移向目的地。因此CCActionEase是用來改變動作的運行時速度的。

CCActionEase是個非常強大的類,子類非常多,這裏只說明其中的幾個:

CCEaseIn:由慢到快

CCEaseOut:由快到慢

CCEaseInOut:先由慢到快,再由快到慢

舉個代碼例子:

CCMoveTo *moveTo = [CCMoveTo actionWithDuration:4 position:ccp(300, 200)];
CCEaseInOut *easeInOut = [CCEaseInOut actionWithAction:moveTo rate:5];
[sprite runAction:easeInOut];
你會看到精靈先由慢到快,再由快到慢。rate參數決定了速率變化的明顯程度,當它大於1時才有效


10.CCGridAction

使用CCGridAction的具體子類可以實現三維效果,例如翻頁效果(CCPageTurn3D)、波浪效果(CCWaves)、流體效果(CCLiquid)。雖然能實現很好看的3D效果,但是它有很大的缺點,如果不啓用深度緩衝,3D效果會有些失真,如果啓用了深度緩衝,會特別耗內存。

如果想開啓深度緩衝的話,就要修改EAGLView的初始化參depthFormat:

EAGLView *glView = [EAGLView viewWithFrame:[window bounds]
								   pixelFormat:kEAGLColorFormatRGB565	
								   depthFormat:GL_DEPTH_COMPONENT24_OES];
可以改爲GL_DEPTH_COMPONENT16_OES(16位深度緩衝)或者GL_DEPTH_COMPONENT24_OES(24位深度緩衝),16位深度緩衝佔用的內存較少,但是仍然會有些失真


瞬時動作

瞬時動作(CCActionInstant)是指能夠瞬間完成的動作,可用於改變節點位置、翻轉節點形成鏡像、設置節點的可視性等。

下面大致看下瞬時動作的繼承結構圖:


看完這個圖,你可能覺得CCActionInstant好像沒有一點使用價值,因爲它的好多動作都可以通過修改節點屬性來完成。比如可以通過設置節點的visible屬性來代替使用CCShow\CCHide\CCToggleVisibility、可以通過修改節點的position屬性來代替使用CCPlace其實當它們與CCSequence結合使用時才有價值。比如,我們想先讓節點運行一個CCMoveTo移動到某個位置,移動完畢後再隱藏節點,這時候我們就可以將CCMoveTo、CCHide兩個動作按順序放進CCSequence中達到想要的效果

// 移動到(300, 200)
CCMoveTo *moveTo = [CCMoveTo actionWithDuration:2 position:ccp(300, 200)];
// 隱藏節點
CCHide *hide = [CCHide action];

CCSequence *sequence = [CCSequence actions:moveTo, hide, nil];

[sprite runAction:sequence];

有時候,在一個動作序列(CCSequence)裏面,我們需要在一個動作運行完畢後,調用某個方法執行一些操作,然後再執行下一個動作。那我們就可以結合CCCallFunc和CCSequence完成這個功能。

比如,我們讓精靈先變爲紅色,再從紅色變爲綠色,再從綠色變爲藍色,而且在每次變換顏色後都調用某個方法執行一些操作:

// 變爲紅色
CCTintTo *tintTo1 = [CCTintTo actionWithDuration:2 red:255 green:0 blue:0];
// 變爲紅色後調用self的turnRed方法
CCCallFunc *fn1 = [CCCallFunc actionWithTarget:self selector:@selector(turnRed)];

// 變爲綠色
CCTintTo *tintTo2 = [CCTintTo actionWithDuration:2 red:0 green:255 blue:0];
// 變爲綠色後調用self的turnGreen:方法,參數是運行當前動作的節點
CCCallFuncN *fn2 = [CCCallFuncN actionWithTarget:self selector:@selector(turnGreen:)];

// 變爲藍色
CCTintTo *tintTo3 = [CCTintTo actionWithDuration:2 red:0 green:0 blue:255];
// 變爲藍色後調用self的turnBlue:data:方法,第一個參數是運行當前動作的節點,第二個參數是data的值
CCCallFuncND *fn3 = [CCCallFuncND actionWithTarget:self selector:@selector(turnBlue:data:) data:@"blue"];

// 最後調用turnDone:方法,傳遞了一個@"done"字符串作爲參數
CCCallFuncO *fn4 = [CCCallFuncO actionWithTarget:self selector:@selector(turnDone:) object:@"done"];

CCSequence *sequence = [CCSequence actions:tintTo1, fn1, tintTo2, fn2, tintTo3, fn3, fn4, nil];
[sprite runAction:sequence];
下面是回調方法的實現:

- (void)turnRed {
    NSLog(@"變爲紅色");
}

// node是運行當前動作的節點
- (void)turnGreen:(id)node {
    NSLog(@"變爲綠色:%@", node);
}

// node是運行當前動作的節點
- (void)turnBlue:(id)node data:(void *)data {
    NSLog(@"變爲藍色,%@,%@", node, data);
}

- (void)turnDone:(id)param {
    NSLog(@"變換完畢:%@", param);
}
你會發現,精靈變爲紅色後就會調用turnRed方法,變爲綠色後會調用turnGreen:方法,變爲藍色後會先調用turnBlue:data:方法,最後調用turnDone:方法

最後做一個總結:

下面這幾個類都會在運行動作時調用一個方法

CCCallFunc :調用方法時不傳遞參數

CCCallFuncN :調用方法時,可以傳遞1個參數,參數值是運行當前動作的節點

CCCallFuncND :調用方法時,可以傳遞2個參數,第1個參數是運行當前動作的節點,第2個參數是actionWithTarget:selector:data:方法中的data值

CCCallFuncO :調用方法時,可以傳遞1個參數,參數值是actionWithTarget:selector:object:方法中的object值


CCRepeatForever

CCRepeatForever直接繼承自CCAction,可以不停地運行某個間隔動作(CCActionInterval)。

如果你想讓精靈不停地旋轉,可以這樣寫:

// 1秒內順時針旋轉360°
CCRotateBy *rotate = [CCRotateBy actionWithDuration:1 angle:360];
// 使用CCRepeatForever重複CCRotateBy動作
CCRepeatForever *repeat = [CCRepeatForever actionWithAction:rotate];
[sprite runAction:repeat];
也能夠利用CCRepeatForever重複一個動作序列(CCSequence)

// 變爲紅色
CCTintTo *tintTo1 = [CCTintTo actionWithDuration:1 red:255 green:0 blue:0];
// 變爲綠色
CCTintTo *tintTo2 = [CCTintTo actionWithDuration:1 red:0 green:255 blue:0];
// 變爲藍色
CCTintTo *tintTo3 = [CCTintTo actionWithDuration:1 red:0 green:0 blue:255];
CCSequence *sequence = [CCSequence actions:tintTo1, tintTo2, tintTo3, nil];

CCRepeatForever *repeat = [CCRepeatForever actionWithAction:sequence];

[sprite runAction:repeat];

你會發現精靈的顏色狀態是:紅 -> 綠 -> 藍 -> 紅 -> 綠 -> 藍 -> 紅 ...,一直在紅綠藍3種顏色之間按順序切換


CCSpeed

CCSpeed也是直接繼承自CCAction,可以影響間隔動作(繼承自CCActionInterval的動作)的運行速度

// 1秒內順時針旋轉360°
CCRotateBy *rotate = [CCRotateBy actionWithDuration:1 angle:360];
// 速度變爲原來的一半
CCSpeed *speed = [CCSpeed actionWithAction:rotate speed:0.5];
[sprite runAction:speed];
本來1秒就完成旋轉的,設置speed爲0.5後,就需要2秒才能完成旋轉
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章