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

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

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

【cocos2d】バッタがジャンプする動きを実装。しかし見えない・・・

cocos2d Objective-C BeeCluster

今回はBeeClusterの4面にバッタを出してみました。
しかしイマイチな結果に・・・

まずは動画をご覧ください。

草むらから弾が飛び出してきて、そのあと虫が飛び出してくる様子がわかりますか?
草むらにはバッタが潜んでいるのですが、そのあまりの保護色っぷりがリアル過ぎました。
これはバッタの色を変えるか草むらの色を変えるかしなければならないようです。
とりあえず、背景を消したバージョンもご覧ください。

このバッタはハチがある距離にいるとジャンプして飛んできます。その距離より遠いときや近いときは弾を撃ってきます。
また、ジャンプ中はアニメーションしますが、地面に止まっているときはアニメーションしません。また、このときはあたり判定もありません。

雑魚キャラなのですが、特殊処理が多いので専用のクラスを作りました。
主な部分の処理はこうなっています。
selfはスプライトで、_targetという非表示のスプライトを追いかけるようになっています。これにより角の取れた滑らかな動きが実現できます。詳しくはこのあたりのポストをご覧ください。
_targetで走らせているCCActionが終了すると、SEL型の_actionMethod変数に入れておいたメソッドをperformSelectorで実行します。この処理はupdateメソッドの中で行っています。
流れ的にはsitメソッドから始まり、ハチとの距離が設定値になるとアクションを強制的に止めjumpメソッドを実行、それが終わったらland, そしてsitへと戻ります。
このように、何らかの契機によって状態遷移させるにはupdateでその条件を常に監視する必要があります。
ご注意!このプログラムにはバグがございます。詳細はこちらのポストをご覧ください。

- (void)update:(ccTime)delta
{
    if (self.tag == kNoType) { //地面にいる場合
        CGPoint touch = ccpAdd([TouchLayer sharedTouch].location, TOUCH_OFFSET);
        CGPoint vector = ccpSub(touch, self.position);
        float distance = ccpLength(vector);
        if (distance <= 200.0 && distance >= 180.0) { // タッチ位置との距離がこの間なら飛び跳ねる
            self.tag = kEnemy;
            [_target stopAllActions];
            _actionMethod = @selector(jump);
        } else {
            CGSize screenSize = [CCDirector sharedDirector].winSize;
            CGRect screenRect = CGRectMake(0, 0, screenSize.width, screenSize.height);
            if (CGRectIntersectsRect(self.boundingBox, screenRect) == YES) {     // 画面の中にいる?
                float difficulty = [DifficultyManager sharedDifficulty].difficulty;
                if (MYRAND(0, 30) <= difficulty) {
                    // 弾を撃つ
                    EnemyBullet* bullet = [EnemyBullet bulletWithPosition:self.position name:@"ball" vector:vector speed:(difficulty*20)+200];
                    [[SpriteBatch sharedSpriteBatch] addChild:bullet z:30]; //他のオブジェクトより手前に表示されるようにする
                }
            }
        }
        self.rotation = 90.0 + CC_RADIANS_TO_DEGREES(-ccpToAngle(vector)); //タッチ方向を向く
    }
    
    if ([_target numberOfRunningActions] == 0) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        [self performSelector:_actionMethod];
#pragma clang diagnostic pop
    }
    if (!_blinking) {
        [self collision]; //点滅中、消えているときはあたり判定しない
    }
    [self steering];
    [self outOfScreen];
    
}

- (void)sit
{
    float speed = 100.0;
    float distance = 2000;
    CGPoint vector = ccp(0, -distance);
    [_target runAction:[CCMoveBy actionWithDuration:distance/speed position:vector]];
}

- (void)jump
{
    float speed = 400.0;
    CGPoint touch = ccpAdd([TouchLayer sharedTouch].location, TOUCH_OFFSET);
    CGPoint vector = ccpSub(touch, self.position);
    vector = ccpMult(vector, 2.0); //通り過ぎるくらい飛ぶ
    float distance = ccpLength(vector);
    
    id scaleUp = [CCScaleTo actionWithDuration:0.2 scale:1.0];
    [self runAction:scaleUp];
    id move = [CCMoveBy actionWithDuration:distance/speed position:vector];
    [_target runAction:move];
    _actionMethod = @selector(land);
    
    // アニメーション・運動特性の設定
    CCAnimation* animation = [self animationWithName:@"locustFly" frameCount:4 delay:0.02];
    id animate = [CCAnimate actionWithAnimation:animation];
    id repeat = [CCRepeatForever actionWithAction:animate];
    [self runAction:repeat];
}

- (void)land
{
    self.tag = kNoType;
    id scaleDown = [CCScaleTo actionWithDuration:0.2 scale:0.8];
    id stopAnimation = [CCCallBlock actionWithBlock:^ {
        [self stopAllActions]; //アニメーションを止める
        CCSpriteFrame* frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"locustSit0.png"];
        [self setDisplayFrame:frame]; //飛んでる絵から止まってる絵に変える
    }];
    [self runAction:[CCSequence actions:scaleDown, stopAnimation, nil]];
    id wait = [CCRotateBy actionWithDuration:0.2 angle:0.0];
    [_target runAction:wait]; // selfのアクションが終わるまで時間待ちselfは惰性で_targetまで移動する
    _actionMethod = @selector(sit);
}