読者です 読者をやめる 読者になる 読者になる

夏までにiPhone アプリつくってみっか!

趣味でiPhone/Androidアプリを開発し、日々勉強した事を書いています。オープンワールド系レースゲームをUnityで開発中です。

【偽スペースハリアー】CCActionを駆使してやられシーンを演出

cocos2d スペースハリアー TravelShooting JP

今回はコリジョン検出を実装し、ハリアーが地上物や空中物に当ったときにやられたりバランスを崩したりするシーンを再現してみました。

本物のスペハリを改めてじっくり観察してみると結構複雑で、久々にcocos2dのCCActionをたくさん使いました。
また、せっかくなのでBGMと音声もつけてみました。

では動画をどうぞ。

地上にある茂みには2種類あるんですが、ぶつかったときのハリアーのリアクションが違うのに気がつきましたか?

また、前回までは地上のチェッカー模様と地上物の動きが完全にはシンクロしていなかったのですが、今回は完全にシンクロするよう3D計算のアルゴリズムを変更しました。
【偽スペースハリアー】迫力を出すため3Dの計算にインチキを投入 - 夏までにiPhone アプリつくってみっか!
で3Dの位置計算にインチキを導入しましたが、今回はインチキのアルゴリズムを変更しました。

安易なインチキだとコリジョン検出などに影響が出そうなので今回は計算に使用する座標にはインチキを入れず、画面に表示するときにインチキを入れました。
遠くのオブジェクトがより遠くに、より速く見えるように、画面奥に行くに従って加速度的にz座標を引き延ばしています。

さて、肝心のやられアクションの再現ですが、CCCallBlockを多用し、スプライトのテクスチャの入れ替え、SEの再生、スクロールの制御など何でもCCActionでシーケンスを組んでコントロールしています。

ハリアーが敵に衝突してから墜落し、再び飛び上がるまでにこれだけのCCActionを実行しています。
墜落までは移動とテクスチャの入れ替えが同時に発生するのでCCSpawnで同時に実行し、それ以降はCCSequenceで順に処理しています。

- (void)actionFallDown
{
#define AHH_UP 80.0
#define UP_SPEED 130.0
#define DOWN_SPEED 300.0
    id texture0 = [CCCallBlock actionWithBlock:^{
        CCSpriteFrame* frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"ahh0.png"];
        [self setDisplayFrame:frame];
    }];
    id texture1 = [CCCallBlock actionWithBlock:^{
        CCSpriteFrame* frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"ahh1.png"];
        [self setDisplayFrame:frame];
    }];
    id texture2 = [CCCallBlock actionWithBlock:^{
        CCSpriteFrame* frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"ahh2.png"];
        [self setDisplayFrame:frame];
    }];
    id texture3 = [CCCallBlock actionWithBlock:^{
        CCSpriteFrame* frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"ahh3.png"];
        [self setDisplayFrame:frame];
        self.position = ccp(self.position.x, self.contentSize.height/2.0);
    }];
    id texture4 = [CCCallBlock actionWithBlock:^{
        CCSpriteFrame* frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"ahh4.png"];
        [self setDisplayFrame:frame];
        self.position = ccp(self.position.x, self.contentSize.height/2.0);
    }];
    id texture5 = [CCCallBlock actionWithBlock:^{
        CCSpriteFrame* frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"ahh5.png"];
        [self setDisplayFrame:frame];
        self.position = ccp(self.position.x, self.contentSize.height/2.0);
    }];
    id texture6 = [CCCallBlock actionWithBlock:^{
        CCSpriteFrame* frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"ahh6.png"];
        [self setDisplayFrame:frame];
        self.position = ccp(self.position.x, self.contentSize.height/2.0);
    }];
    id texture7 = [CCCallBlock actionWithBlock:^{
        CCSpriteFrame* frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"ahh7.png"];
        [self setDisplayFrame:frame];
        self.position = ccp(self.position.x, self.contentSize.height/2.0);
    }];
    id texture8 = [CCCallBlock actionWithBlock:^{
        CCSpriteFrame* frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"harrier_fly0.png"];
        [self setDisplayFrame:frame];
        self.position = ccp(self.position.x, self.contentSize.height/2.0);
    }];
    
    id stopControl = [CCCallBlock actionWithBlock:^{
        _controlPaused = YES;
        [Scene3D sharedScene3D].zScrollFixed = YES;
        [Scene3D sharedScene3D].xScrollFixed = YES;
        [TouchLayer sharedTouch].atBottomCenter = YES;
        [self stopAction:_repeat];
    }];
    id resumeLRControl = [CCCallBlock actionWithBlock:^{
        _controlPaused = NO;
        [TouchLayer sharedTouch].atBottomCenter = NO;
        [TouchLayer sharedTouch].atBottomFly = YES;
    }];
    id resumeRun = [CCCallBlock actionWithBlock:^{
        [Scene3D sharedScene3D].zScrollFixed = NO;
        [TouchLayer sharedTouch].atBottomFly = NO;
        [TouchLayer sharedTouch].atBottom = YES;
        [self runAction:_repeat];
    }];
    id resumeFullControl = [CCCallBlock actionWithBlock:^{
        [Scene3D sharedScene3D].xScrollFixed = NO;
        [TouchLayer sharedTouch].atBottom = NO;
    }];
    id stopCollision = [CCCallBlock actionWithBlock:^{
        _collisionPaused = YES;
    }];
    id resumeCollision = [CCCallBlock actionWithBlock:^{
        _collisionPaused = NO;
    }];
    
    CGFloat upDuration = AHH_UP/UP_SPEED;
    CGFloat downDuration = (self.position.y + AHH_UP)/DOWN_SPEED;
    
    id moveUp = [CCMoveBy actionWithDuration:upDuration position:ccp(0.0, AHH_UP)];
    
    id moveDown = [CCMoveTo actionWithDuration:downDuration position:ccp(self.position.x, 24.0)];
    
    id blinkShort = [CCBlink actionWithDuration:0.8 blinks:5];
    id blinkLong = [CCBlink actionWithDuration:1.6 blinks:10];
    
    id ahh = [CCCallBlock actionWithBlock:^{
        [[SimpleAudioEngine sharedEngine] playEffect:@"ahh.aiff"];
    }];
    id ready = [CCCallBlock actionWithBlock:^{
        [[SimpleAudioEngine sharedEngine] playEffect:@"getready.aiff"];
    }];
    
    id animSeq1 = [CCSequence actions:
                   texture0,
                   [CCDelayTime actionWithDuration:10/60.0],
                   texture1,
                   [CCDelayTime actionWithDuration:16/60.0],
                   texture2,
                   [CCDelayTime actionWithDuration:16/60.0],
                   texture3,
                   nil];
    
    id animSeq2 = [CCSequence actions:
                   texture4,
                   [CCDelayTime actionWithDuration:7/60.0],
                   texture5,
                   [CCDelayTime actionWithDuration:5/60.0],
                   texture6,
                   [CCDelayTime actionWithDuration:6/60.0],
                   texture7,
                   [CCDelayTime actionWithDuration:7/60.0],
                   texture8,
                   [CCDelayTime actionWithDuration:18/60.0],
                   nil];
    
    id moveSeq1 = [CCSequence actions:
                    stopControl,
                    stopCollision,
                    moveUp,
                    moveDown,
                   [CCDelayTime actionWithDuration:1.0],
                   nil];
    id moveSeq2 = [CCSequence actions:
                   
                   resumeLRControl,
                   blinkShort,
                   resumeRun,
                   blinkShort,
                   resumeFullControl,
                   blinkLong,
                   resumeCollision,
                   nil];
    id fall = [CCSpawn actions:animSeq1, moveSeq1, nil];
    id sequence = [CCSequence actions:ahh, fall, animSeq2, ready, moveSeq2, nil];
    [self runAction:sequence];

}