cocos2dでアクションを使う – アクションの種類を知る.
cocos2dでのレイヤーやスプライトの配置の仕方が大体わかった所で、今度はそれらオブジェクトにアクションを追加したいと思います。
cocos2dのアニメーションはOpenGLのようにdraw関数があって毎フレームごとにパラメータの値を変えながら制御するというものではありません。
どのメソッド内でもいい(おそらく)ので、アクションメソッドを呼び出せば、オブジェクトにアクションを起こさせることができます。基本的なcocos2dのアクションは以下の様なプロセスで行われます。
- オブジェクトに追加したいアクションを定義する(アクションの種類、終了までに要する時間など)
- 任意のメソッド内でアクションを追加したいオブジェクトに向け、アクション開始メッセージを送る
- メッセージが送られた時点からアクションが開始される。
- 1で設定した時間をかけてアクションが行われる。
処理はバックグラウンドで行われるので、基本的にはプログラム内で気にかける必要はありません。なんて簡単なんだ。OpenGLをCでやっていた僕にとっては革命的な簡単さ。
アクションの設定
さて、さっそくアクションを追加してみましょう。initにスプライトを読み込んで、それにアクションを付けてみます。
-(id) init { if( (self=[super init]) ) { CGSize wSize = [[CCDirector sharedDirector] winSize]; CCSprite* circle = [CCSprite spriteWithFile:@"bb_pic01.png"]; circle.position = ccp(0.0f, wSize.height / 2); [self addChild:circle]; CCMoveTo* move = [CCMoveTo actionWithDuration:5.0 position:ccp(wSize.width, wSize.height / 2)]; [circle runAction:move]; } return self; }
まず、8行目でオブジェクトを画面の左端に配置しています。そして、11行目でアクションの定義をしています。今回は左端から右端まで移動させてみます。
アクションの定義にはまず、アクションオブジェクトを生成しなければなりません。今回は移動させるアクションなのでCCMoveToクラスを使用しました。cocosでは他にも様々なアクションクラスが用意されているので、自分が使いたいアクションクラスを指定すればいいです。どのようなアクションが他にあるのか、詳細は後でまとめたいと思います。また、ここではCCMoveTo*とクラス指定していますが、クラス指定せずにid*としても構いません。
11行目の後半はアクションのパラメータ設定です。CCMoveToクラスメソッドを呼び出し、まずアクションに要する時間’Duration’を5秒、最終的に到達するポジションを次のパラメータで指定しています。ccpは2次元座標値を設定するCGPointのクラスメソッドです。ここで右端を指定しています。こうすることで、’5秒かけて左端から右端まで移動するアクション’が定義されます。
そして12行目でスプライトにこのアクションを割当て、アクションを開始しています。 実行すると起動と同時に画像が左から右へ移動します。
今はイニシャライザでこのアクションを読んでいるため、起動と同時にアクションが開始されていますが、例えば、タッチイベントが発生した時にこのメソッドを呼び出せば、タッチに反応するアクションを作ることができます。
アクションの種類
cocos2dに用意されているアクションを簡単に列挙しておきます。
- 平行移動 − CCMoveTo、CCMoveBy
- 回転 − CCRotateTo、CCRotateBy
- 拡大、縮小 − CCScaleTo、CCScaleBy
- スキュー − CCSkewTo、CCSkewBy
- ジャンプ − CCJumpTo、CCJumpBy
- 点滅 − CCBlink
- フェード − CCFadeIn、CCFadeOut、CCFadeTo
- 色変化 − CCTintTo、CCTintBy
こんなところでしょうか。あとは自分が設定した曲線にオブジェクトを沿わせて移動させるCCBezierTo、CCBezierByなんてのもあります。
またToとByですが、Toが絶対値、Byが相対値に伴うアクションとなります。例えばMoveToでポジション(5, 0)を設定されたなら、画面もしくはそのオブジェクトがいるノードの(5, 0)の位置へ移動します。一方、MoveByで(5, 0)なら自分がいる位置から5ピクセル右に行った位置に移動するアクションになります。
ではScaleToとScaleByはどのような挙動になるのでしょうか。
実験してみます。
2つの画像を画面に配置し、拡大率を両方共0.5にしておきます。片方はCCScaleToでスケールパラメータを2に指定。もう一方はCCScaleByでスケールパラメータを2に指定しておきます。
-(id) init { if( (self=[super init]) ) { CGSize wSize = [[CCDirector sharedDirector] winSize]; CCSprite* circle1 = [CCSprite spriteWithFile:@"bb_pic01.png"]; circle1.position = ccp(50, wSize.height / 2); circle1.scale = 0.5; [self addChild:circle1]; CCScaleTo* scaleTo = [CCScaleTo actionWithDuration:5 scale:2]; [circle1 runAction:scaleTo]; CCSprite* circle2 = [CCSprite spriteWithFile:@"bb_pic01.png"]; circle2.position = ccp(wSize.width - 50, wSize.height / 2); circle2.scale = 0.5; [self addChild:circle2]; CCScaleBy* scaleBy = [CCScaleBy actionWithDuration:5 scale:2]; [circle2 runAction:scaleBy]; } return self; }
すると以下の様な結果になりました。
ScaleToの方は元画像の2倍の大きさになっています。一方ScaleByの方は元画像の大きさになっています。このことから、ScaleByは指定スケール値を現在のオブジェクトのスケールに掛けた値がアクション終了時の値になっているということがわかります。
アクションの組み合わせ
「移動してから拡大する」ようなアクションはどのように設定するのでしょうか。
このようなアクションの組み合わせにはCCSequenceというクラスを使います。配列のようにアクションを列挙することで、アクションを順番に実行していってくれます。
また、「移動しながら拡大する」ようなアクションにはCCSpawnが使えます。Sequenceのようにアクションを列挙するのですが、それらを同時に実行してくれます。
このようにcocos2dにはアクションを管理するクラスも揃っています。
- アクションの遅延 − CCDelayTime
- アクションの同時実行 − CCSpawn
- アクションの順次実行 − CCSequence
- アクションのリピート − CCRepeat、CCRepeatForever
- アクションのリバース − reverseメソッド
reverseメソッドは指定したアクションを逆向けに実行するアクションオブジェクトを作ってくれます。また、SpawnをSequenceに入れ込んだりSequenceをRepeatに入れ込んだりすることができるので、それらを組み合わせることで思い通りにアクションを組み立てることができます。
アクションの組み合わせ例
実際にアクションを色々組み合わせた例を上げておきます。
作ったアクションは、
「”左端から右へ300 pixel分、大きさを拡大しながら移動→2秒停止→右から左へ300 pixel縮小しながら移動(左から右のリバース)”、これを永遠繰り返す」
です。
以下の様なコードで実現出来ます。
-(id) init { if( (self=[super init]) ) { CGSize wSize = [[CCDirector sharedDirector] winSize]; CCSprite* circle1 = [CCSprite spriteWithFile:@"bb_pic01.png"]; circle1.position = ccp(0, wSize.height / 2); circle1.scale = 0.5; [self addChild:circle1]; CCMoveBy* moveBy = [CCMoveBy actionWithDuration:5 position:ccp(300, 0)]; CCScaleBy* scaleBy = [CCScaleBy actionWithDuration:5 scale:2]; CCSpawn* spawn = [CCSpawn actions:moveBy, scaleBy, nil]; CCDelayTime* delay = [CCDelayTime actionWithDuration:1]; CCSequence* seq = [CCSequence actions:spawn, delay, nil]; CCSequence* wholeSeq = [CCSequence actions:seq, [seq reverse], nil]; CCRepeatForever* forever = [CCRepeatForever actionWithAction:wholeSeq]; [circle1 runAction:forever]; } return self; }
12、13、14行目で、移動、拡大の設定とそれらを同時に行うという設定をしています。MoveBy、ScaleByを使っているのは20行目でreverseメソッドを使うためです。reverseメソッドはToアクションには対応出来ませんのでここではByを使っています。
16行目で待ち時間を1秒に設定し、spawnとdelayでシーケンスseqを作っています。
20行目では更にseqのリバースを作りそれをseqのあとに行うことでwholeSeqという行って帰ってくるアクションを作っています。待ち時間が2秒になるのは、右に行った際、delayが連続で実行されるためです。
22行目でwholeSeqをずっと繰り返すという設定をしたforeverオブジェクトを作っています。
最後にforeverをcircle1スプライトに設定して、アニメーションを開始しています。
このように複雑なアニメーションでも、様々なアクションを組み合わせることで実現することが可能です。
次回は、アクションももっとイケてるアクションにする”イージング”について見て行きたいと思います。