cocos2dでアクションを使う – アクションの応用.
アクションの基本的な使い方を理解したので、もう少し発展的な部分を紹介したいと思います。
今回解説するのは、アクション中または終了後に特定の処理を実行する方法です。
cocos2dでアクションを使っていると、このアクションが終わった時に何か処理をさせたいと思うことがよくあります。このような時を想定し、cocos2dにはCCCall…というクラス群が用意されています。例えば、’CCallFunc’はプログラム内に書かれているメソッドを呼び出し、実行してくれます。ですので、これを用いてアクションオブジェクトを作り、それをCCSequence内に入れてやれば、アクションの中で呼び出してくれます。
このようなCCCallクラス群を一つ一つ見て行きましょう。
CCCallBlock
アクション中に実行したい処理を直接記述し、アクションオブジェクトとしてそのブロックを定義します。以下の様なコードで記述します。
// CCCallBlock* block = [CCCallBlock actionWithBlock:^{ /*実行したい処理*/ }]; //
実際に、画像を右に100 pixel移動させた後、コンソールに「Hello」と出力するアクションは以下の様なコードになります。
-(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); [self addChild:circle1]; CCMoveBy* moveBy = [CCMoveBy actionWithDuration:3 position:ccp(100, 0)]; CCCallBlock* block = [CCCallBlock actionWithBlock:^{ NSLog(@"Hello"); }]; CCSequence* seq = [CCSequence actions:moveBy, block, nil]; [circle1 runAction:seq]; } return self; }
NSLogでHelloと出力する処理を記述しそれをブロックにしています。それをシーケンスでmoveByの後に実行するよう指定しています。
CCCallBlockN
CCCallBlockに引数として、アクションを実行しているノードを用いることができます(CCNodeを継承しているノードのみ:CCLayerやCCSpriteなど)。例えば、先ほどのコードでスプライトのサイズを出力しようとするなら、以下のように書き換え、ブロック内でスプライトのコンテントサイズを呼び出してやれば、実現出来ます。
CCMoveBy* moveBy = [CCMoveBy actionWithDuration:3 position:ccp(100, 0)]; CCCallBlockN* block = [CCCallBlockN actionWithBlock:^(CCNode* circle){ NSLog(@"Circle size: %f, %f", circle.contentSize.width, circle.contentSize.height); }]; CCSequence* seq = [CCSequence actions:moveBy, block, nil]; [circle1 runAction:seq];
CCCallBlockO
CCCallBlockNと使用は似ていますが、用いる引数はCCNodeを継承しているノードでなくて構いません。以下の様な構文で記述します。
// CCCallBlockO* block = [CCCallBlockO actionWithBlock:^(id object)block object:(id)]; //
第2引数の’object:(id)’でブロック内で用いたいオブジェクトを指定します。それが第一引数の’object’としてブロック内で使われます。
わかりやすくするため、以下の様なプログラムを書きました。先程はアクションを起こしているスプライトのサイズを出力しましたが、今回はアクションとは関係のないHelloWorldLayer(このinitメソッドが書かれているクラス)のサイズを出力するようにしました。プログラム内ではselfで記述されています。(selfでアクセスできるので本当はBlockO で書く必要はなく、CCCallBlockで対応するべきですが今回は実験のため。)
-(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); [self addChild:circle1]; CCMoveBy* moveBy = [CCMoveBy actionWithDuration:3 position:ccp(100, 0)]; CCCallBlockO* block = [CCCallBlockO actionWithBlock:^(CCNode* hello){ NSLog(@"HelloWorldLayer size: %f, %f", hello.contentSize.width, hello.contentSize.height); } object:self]; CCSequence* seq = [CCSequence actions:moveBy, block, nil]; [circle1 runAction:seq]; } return self; }
HelloWorldLayerのレイヤーサイズが出力されたでしょうか。
CCCallFunc
CCCallFuncは今までブロックで書かれていた処理を別のメソッドとして書きそこにアクセスするための処理です。僕自身は、アクション終わりでたくさんの処理をすることが多いので、Blockクラスよりも今から紹介するFuncクラス群のほうをよく使います。
以下の構文で書きます。
CCCallFunc* func = [CCCallFunc actionWithTarget:(id) selector:(SEL)];
第二引数のSELですが、メソッドをセレクターとして扱うために、”@selector (/*メソッド名*/)”を使用します。では実際に例として、Helloと出力する’sayHello’メソッドを同クラス内に定義し、アクション終了時に呼び出すようにしてみます。
-(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); [self addChild:circle1]; CCMoveBy* moveBy = [CCMoveBy actionWithDuration:3 position:ccp(100, 0)]; CCCallFunc* func = [CCCallFunc actionWithTarget:self selector:@selector(sayHello)]; CCSequence* seq = [CCSequence actions:moveBy, func, nil]; [circle1 runAction:seq]; } return self; } -(void)sayHello { NSLog(@"Hello"); }
‘actionWithTarget’のidはメソッドが書かれているオブジェクトを指定します。ここではHelloWorldLayer内に書かれているのでselfです。CCCallBlockの時と同様CCSequenceでmoveByの後に記述することで、スプライトの移動が終わった瞬間に’sayHello’メソッドが呼び出されます。
CCCallFuncN
BlockNの時のように、アクションを行なっているノードを引数としてメソッド内で使うことができます。CCCallFuncと比べ、メソッド宣言の書き方が少し異なります。実例を見てみましょう。sayHello内でスプライトのサイズを出力させてみます。
// ~~~~ //省略 CCMoveBy* moveBy = [CCMoveBy actionWithDuration:3 position:ccp(100, 0)]; CCCallFuncN* func = [CCCallFuncN actionWithTarget:self selector:@selector(sayHello:)]; CCSequence* seq = [CCSequence actions:moveBy, func, nil]; [circle1 runAction:seq]; } return self; } -(void)sayHello:(CCNode*)node { NSLog(@"circle size: %f, %f", node.contentSize.width, node.contentSize.height); }
sayHelloの引数nodeには、このアクションが実行されるcircle1が入り、NSLogでそのサイズを出力しています。
CCCallFuncND
このクラスはCCCallFuncNにもう一つvoid*型の引数を一つ渡すことができます。今回はoffsetというint型のデータをsayHelloに渡してみたいと思います。以下のように記述します。
//省略 int offset = 50; CCMoveBy* moveBy = [CCMoveBy actionWithDuration:3 position:ccp(100, 0)]; CCCallFuncND* func = [CCCallFuncND actionWithTarget:self selector:@selector(sayHello:data:) data:offset]; CCSequence* seq = [CCSequence actions:moveBy, func, nil]; [circle1 runAction:seq]; } return self; } -(void)sayHello:(CCNode*)sender data:(int)offset { NSLog(@"circle size: %f, %f", sender.contentSize.width + offset, sender.contentSize.height + offset); }
実行すると、スプライトのサイズにoffsetの50を加算した値が出力されます。
CCCallFuncO
このクラスはCCCallBlockOと同様、ノードの代わりに好きなオブジェクトを渡すことができます。今回もHelloWorldLayerを渡してみましょう。
//省略 CCMoveBy* moveBy = [CCMoveBy actionWithDuration:3 position:ccp(100, 0)]; CCCallFuncO* func = [CCCallFuncO actionWithTarget:self selector:@selector(sayHello:) object:self]; CCSequence* seq = [CCSequence actions:moveBy, func, nil]; [circle1 runAction:seq]; } return self; } -(void)sayHello:(CCNode*)hello { NSLog(@"hello size: %f, %f", hello.contentSize.width, hello.contentSize.height); }
実行すると、HelloWorldLayerのサイズが出力されます。
このようにCCCallクラスを使うことで、アクション内や終了時に様々な処理を行うことができます。
次回は、アクションを使うにあたって知っておくべきことを紹介します。
One Comment
Pingbacks