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

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

【cocos2d】addChildのzパラメーターでスプライトを順序よく重ね合わせる

BeeClusterの最終面では蜂の巣から幼虫が飛び出してくるという演出を考えています。
蜂の巣を斜め上から見下ろしているようなアングルになります。
幼虫が巣の各部屋の中に入っているように見せるには、幼虫は上の壁と下の壁の間に重ね合わせる必要があります。
従いまして、巣は一枚のスプライトではなく、何枚ものスプライトを重ね合わせて表現します。
そこで、こんな絵を描きました。
f:id:takujidev:20130610000904p:plain
これを上下左右に並べそれぞれのスプライトをaddChildするときのzパラメーターを適切に設定する事で間にハチの幼虫を入れる事が可能になります。
実際の画面はこのようなイメージになります。
まだ幼虫の絵を描いていないのでハエで代用しています。
まだ作りかけなのでいろいろと不自然な点がありますが、ご容赦ください。

ハエが巣の奥から手前へ出てくるのがわかりますか?
プログラムの現状に実装はこのようになっています。

#import "Honeycomb.h"
#import "SpriteBatch.h"
#import "Enemy.h"
#import "Collision.h"
#import "LoadingScene.h"

@implementation Honeycomb {
    __weak CollisionSprite* _honeycomb[6][3];
}

+ (id)enemyWithPosition:(CGPoint)position type:(NSString *)type name:(NSString *)name attackPoint:(float)attackPoint life:(float)life
{
    return [[self alloc] initWithPosition:position type:type name:name attackPoint:attackPoint life:life];
}

- (id)initWithPosition:(CGPoint)position type:(NSString *)type name:(NSString *)name attackPoint:(float)attackPoint life:(float)life
{
    if ((self = [super initWithSpriteFrameName:@"honeycomb.png"])) {
        
        self.visible = NO; //SpriteBatchNodeのchildとするためテクスチャーを読むが表示はしない
        
        // ハニカムの生成
        CGSize winSize = [CCDirector sharedDirector].winSize;
        float x;
        float y = 480;
        float stepX = -113;
        float stepY = 11;
        int zOffset = -200;
        
        for (int i = 0; i < 6; i++) {
            if ((i % 2) == 1) {
                x = winSize.width + 19;
            } else {
                x = winSize.width;
            }
            float posY = y + (i * stepY);
            for (int j = 0; j < 3; j++) {
                _honeycomb[i][j] = [CollisionSprite spriteWithSpriteFrameName:@"honeycomb.png"];
                [[SpriteBatch sharedSpriteBatch] addChild:_honeycomb[i][j] z:(zOffset+i*20+j)];
                _honeycomb[i][j].anchorPoint = ccp(1, 1); //右上で位置決めする
                float posX = x + (j * stepX);
                _honeycomb[i][j].position = ccp(posX, posY);
            }
        }
        
        // 門の生成
        CollisionSprite* gate = [CollisionSprite spriteWithSpriteFrameName:@"stage6-FGEnd.png"];
        [[SpriteBatch sharedSpriteBatch] addChild:gate z:-1];
        gate.scale = 2.0;
        gate.anchorPoint = ccp(0, 0);
        gate.position = ccp(0, 250);
        
        // 門の影の生成
        CollisionSprite* shadow = [CollisionSprite spriteWithSpriteFrameName:@"stage6-FGShadow.png"];
        [[SpriteBatch sharedSpriteBatch] addChild:shadow z: -210];
        shadow.scale = 2.0;
        shadow.anchorPoint = ccp(0, 0);
        shadow.position = ccp(0, 250);
        
        // 幼虫の生成
        y = 420;
        zOffset = -190;
        for (int i = 0; i < 5; i++) {
            if ((i % 2) == 1) {
                x = 100;
            } else {
                x = 81;
            }
            float posY = y + (i * 11);
            for (int j = 0; j < 5; j++) {
                float posX = x + (j * 38);
                Enemy* larva = [Enemy enemyWithPosition:ccp(posX, posY) type:@"larva" name:@"larva" attackPoint:30 life:30];
                [[SpriteBatch sharedSpriteBatch] addChild:larva z:(zOffset+i*20+j)];
            }
        }
        
        [self schedule:@selector(checkLarva:) interval:1.0];
    }
    return self;
}

- (void) checkLarva:(ccTime)delta
{
    CCNode* object;
    object = [[SpriteBatch sharedSpriteBatch] getChildByTag:kLarva];
    // 幼虫が全滅したら蜂の巣を消してラスボスを出す
    if (!object) {
        [self removeHoneycomb];
        [self unschedule:@selector(checkLarva:)];
    }
}

- (void) removeHoneycomb
{
    for (int i = 0; i < 6; i++) {
        for (int j = 0; j < 3; j++) {
            [_honeycomb[i][j] runAction:[CCMoveBy actionWithDuration:5 position:ccp(0, 200)]];
        }
    }
}

- (void)collisionDetectedWith:(CollisionSprite *)sender
{
    // 今のところ何もしない
}

@end

巣の各パーツやハエの表示位置は試行錯誤して少しずつ調整しました。
巣は影の部分があるので上下だけでなく左右の重ね合わせも正確にする必要があります。
右側から並べているのはそのためです。

蜂の巣はハエを全て倒すと上に移動して消えます。
後から巣の各パーツを配列に保持しているのはあとからCCActionを掛けられるようにするためです。

ハエが全て倒された事を判定するため、tagプロパティに専用の値を入れています。
1秒に1回、getChildByTagメソッドで生き残りがいるかどうかをチェックします。
そのtagを持つスプライトが存在しない場合はnilが返りますので、蜂の巣をどける処理を行います。それ以降はチェックをしないようにunschduleでスケジュールを止めます。
まだ実装してせんが、その後ラスボスを生成し、ラスボスが倒されたかどうかチェックするためのスケジュールを掛けます。

このhoneycombというクラスは通常の敵生成ルーチンで生成されますが、実体はありません。
物理的な敵そのものではなく、この面のボス戦全般を管理するクラスといえます。
スプライトバッチノードを使う都合上一応テクスチャーをロードしていますが、実際にはself.visible = NOと設定していますので、このインスタンスそのものは表示されません。
このような複雑な機能を持つクラスが、普通のハエのスプライトと同じ手続きで生成され、あとは勝手にボス戦の演出をしてくれます。
このあたりはオブジェクト指向プログラミングの面白いところだと思います。