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

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

【cocos2d】仲間キャラを実装してみた

前回作成したタップ検出機能を使って味方キャラをを仲間に入れる機能を実装してみました。
味方キャラなのですが、出現部分は敵キャラ生成ルーチンにそのまま便乗します。
従って、当たり判定のない敵として現れ、タップされると本当の味方キャラを生成し、自分はそれと入れ替わりで消滅するようなつくりにしました。
まずは動画をご覧ください。
今回からタイトルがついて本番用の背景になって、敵キャラも大雑把に配置しています。

画面にちょくちょく現れる小さめのハチが味方キャラです。地面に止まっているという設定で、背景のスクロール速度と移動速度を合わせましたが、ちょっと地味でした。また、大きさのバランスも悪いので、今度修正します。
このハチはタップされたタイミングで飛び上がり、集団に合流し、仲間に入ります。

イニシャライザーの実装はこのようになっています。

- (id)initWithPosition:(CGPoint)position type:(NSString *)type name:(NSString *)name attackPoint:(float)attackPoint life:(float)life
{
    if ((self = [super initWithSpriteFrameName:@"beeUpSideDown.png"])) { //進行方向逆向きの絵にする
        self.radius = self.contentSize.width/3.0; //デフォールト値
        self.tag =kNoType;
        self.attackPoint = attackPoint;
        self.life = life;
        self.position = position;
        self.scale = 0.7; //遠くにいるように小さく表示
        
        // デフォールトの運動特性
        _maxAccel = 100/FPS;
        _maxSpeed = 500/FPS;
        _brakeDistance = 10.0;
        
        // タップ終了イベント発生の連絡をもらう
        [[TouchLayer sharedTouch] registerRecipient:self];
                
        // ターゲットにアクションを設定 クリックされなければそのまま画面外に出て解放される
        CGSize winSize = [CCDirector sharedDirector].winSize;
        _target = [CollisionSprite node];
        _target.position = position;
        [[ParentNode sharedParentNode] addChild:_target];
        id moveDown = [CCMoveBy actionWithDuration:120.0 position:ccp(0, -(6000 - winSize.height))]; //スクロールの速度に合わせる
        [_target runAction:moveDown];
        [self scheduleUpdate];
    }
    return self;
}

この処理で、タップイベントをもらうためにTouchLayerに自分自身を登録しています。
[[TouchLayer sharedTouch] registerRecipient:self];
タップイベントの通知についてはこちらのポストをご参照下さい。
タップされたときに呼ばれるメソッドがこちらです。

- (void)touchNotification:(CGPoint)location
{
    // 自分の上でタップされたらタッチ場所に飛んで行ってBeeを生成する
    float distance = ccpDistance(self.position, location);
    if (distance > self.contentSize.width) {
        return;
    }
    
    [_target stopAllActions];
    float speed = 100;
    CGPoint touch = [TouchLayer sharedTouch].location;
    touch = ccpAdd(touch, TOUCH_OFFSET);
    float flyDistance = ccpDistance(touch, self.position);
    id flyToTouch = [CCMoveTo actionWithDuration:flyDistance/speed position:touch];
    id scaleUp = [CCScaleTo actionWithDuration:flyDistance/speed scale:1.0]; //通常の大きさにする
    id createBee = [CCCallBlock actionWithBlock:^{
        [[SpriteBatch sharedSpriteBatch] addChild:[Bee beewithPosition:self.position]]; //Beeを生成
        [_target removeFromParentAndCleanup:YES]; //ターゲットを解放
        _target = nil;
        [[TouchLayer sharedTouch] unregisterRecipient:self]; //タッチ通知のArrayから外してもらう
        [self removeFromParentAndCleanup:YES]; //自分を削除
    }];
    id spawn = [CCSpawn actions:flyToTouch, scaleUp, nil];
    id sequence = [CCSequence actions:spawn, createBee, nil];
    [_target runAction:sequence];

    // アニメーション開始
    CCAnimation* animation = [self animationWithName:@"bee" frameCount:4 delay:0.1];
    id animate = [CCAnimate actionWithAnimation:animation];
    id repeat = [CCRepeatForever actionWithAction:animate];
    [self runAction:repeat];
}

ccpDistanceでタッチ位置と自分の位置の距離を求め,近くがタップされていればタップされたと判定しています。contentSize.widthはスプライトの幅、distanceは中心からの距離となります。したがいまして、自分の幅の倍離れた位置でもタップしていると見なしています。また、cocos2dではscaleをかけてもcontentSizeは変化しないので、スプライトの見た目からするとかなり許容範囲が広いですが、このくらいゆるい方がストレスなく遊べます。
なお、TOUCH_OFFSETには50くらいの値が入っています。ハチの集団が自分の指で隠れて見えなくならないように、プログラム全般でタッチ位置にオフセットを掛けています。これを入れないと自分の指からミサイルが発射されているように見えてしまいます。