Prainブログ

ゲーム開発とかIT小話とかその他雑記のブログ

*

ゲーム制作 Cocos2d-x関連 第12回 「ボールヒットエフェクトの表示」

      2016/08/17

派手なヒットエフェクトが欲しい!

 

この回では、派手では無いですが、ボールがドロップにヒットしたタイミングでヒットエフェクトを表示していきたいと思います。

一口にエフェクトと言っても色々なやり方がありますが、ここではシンプルに1枚の画像アニメーションを使用しながら表示するやり方を紹介します。

hit_effect

 

以下のアニメーションのような感じです。

hiteffect

 

この程度のアニメーションでも、今までと比べると少し難しく感じると思います。ですがゲームプログラムに必要なことが詰まっている回だと思いますので、なるべくわかりやすく紹介できれば幸いです。

 

8/17追記

複数の画像とアニメーション機能を利用する、よりリッチなエフェクト演出のやり方記事を追加しました。

この記事では、Cocos2d-xのアニメーションを利用したエフェクトの表示方法について紹介します。  また、少し実践的なアニメーションの利用方法をシリーズ記事として全5回で予定しています。 ・第1回 : アニメーションを利用した回復エフェクトの表...

 

 

スポンサーリンク

 

 

リソースの追加

まずはヒットエフェクト画像を保存して、Xcodeのresource配下にドラッグアンドドロップしてください。

やり方を忘れてしまった方は第2話 「Cocos2d-xで作ろう!!~画像の表示処理」を参考にしてください。それではプログラムを実装していきましょう。

 

 

プログラムの実装

HelloWorldScene.h

void viewHitEffect(cocos2d::Vec2 pos); // ヒットエフェクトを表示する

 

 

HelloWorldScene.cpp HelloWorld::viewHitEffect

void HelloWorld::viewHitEffect(Vec2 pos){
    // ヒットエフェクトの生成
    Sprite* hitEffect = Sprite::create("hit_effect.png");
    hitEffect->setPosition(pos);
    addChild(hitEffect, 10);
    
    // ヒットエフェクトのアニメーション
    auto scaleTo = ScaleTo::create(0.1, 2.0);
    auto fadeTo = FadeTo::create(0.1, 0);
    auto spawn = Spawn::create(scaleTo, fadeTo, nullptr);
    
    // ヒットエフェクトを表示し終えたらヒットエフェクトを削除
    auto removeHitEffect = CallFunc::create([hitEffect](){
        hitEffect->removeFromParent();
    });
    
    // ヒットエフェクトの一連の流れ開始
    auto seq = Sequence::create(spawn, removeHitEffect, nullptr);
    hitEffect->runAction(seq);
    
    
}

 

 

HelloWorldScene.cpp HelloWorld::update


void HelloWorld::update(float dt){
    if(_ball->_isBallMoving){
        float x = _ball->getPosition().x - _ball->_speed*cosf(CC_DEGREES_TO_RADIANS(_ball->_degree));
        float y = _ball->getPosition().y + _ball->_speed*sinf(CC_DEGREES_TO_RADIANS(_ball->_degree));
        _ball->setPosition(Vec2(x, y));
         
         
        // ドロップに接触した場合の跳ね返りの処理
        std::list<Sprite*>::iterator it;
        for(it = _dropList.begin(); it != _dropList.end(); it++){
            if(hitDetectionOval(_ball, (*it))){
                // 跳ね返り角度の更新
                _ball->_degree = getDegree(_ball->getPosition(), (*it)->getPosition());

                // 効果音
                CocosDenshion::SimpleAudioEngine::getInstance()->playEffect("reflection.mp3");

                // ヒットエフェクトの表示
                Vec2 pos = Vec2(ccpMidpoint(_ball->getPosition(), (*it)->getPosition()));
                viewHitEffect(pos);
            }
        }
         
        // 画面端に接触した場合の跳ね返りの処理
        Size visibleSize = Director::getInstance()->getVisibleSize();
        // 画面下端
        if(_ball->getPosition().y - _ball->getContentSize().height / 2 <= 0){ _ball->_degree = _ball->_degree * -1;
            y = _ball->getContentSize().height / 2;
        }
         
        // 画面上端
        if(_ball->getPosition().y + _ball->getContentSize().height / 2 >= visibleSize.height - _enemy->getContentSize().height){
            _ball->_degree = _ball->_degree * -1;
            y = visibleSize.height - _ball->getContentSize().width / 2 - _enemy->getContentSize().height;
        }
         
        // 画面左端
        if(_ball->getPosition().x - _ball->getContentSize().width / 2 <= 0){ _ball->_degree = 180 - _ball->_degree;
            x = _ball->getContentSize().width / 2;
        }
         
        // 画面右端
        if(_ball->getPosition().x + _ball->getContentSize().width / 2 >= visibleSize.width){
            _ball->_degree = 180 - _ball->_degree;
            x = visibleSize.width - _ball->getContentSize().width / 2;
        }
         
        _ball->setPosition(Vec2(x, y));
         
         
 
        // 減速処理
        _ball->_speedDownCount++;
        // 一定回数をカウントしたら徐々に減速する
        if(_ball->_speedDownCount > 100){
            // スピードが0になったらムーブフラグをfalseにする。減速したスピードを元に戻し、スピードダウンカウントを0に初期化する
            if(_ball->_speed <= 0){ // 減速していたスピードを元に戻す _ball->_speed = 50;
 
                // ボール移動中フラグを元に戻す
                _ball->_isBallMoving = false;
 
                // カウンタのリセット
                _ball->_speedDownCount = 0;
 
            }else{
                // 減速処理
                _ball->_speed -= 1;
  
            }
        }
    }
 
}

 

 

プログラム解説

HelloWorld::viewHitEffectは自作のメソッドです。引数のVec2の場所にヒットエフェクト生成し、「拡大アクション」「フェードアウトアクション」「同時に」行いながら表示しています。また「アクションが完了したらヒットエフェクトを削除」しています。

それでは順番に説明していきます。

 

アクションについて

スプライト画像にアクションを設定してやると、設定されたアクションに応じてアニメーションを行います。

例えばプログラム中で「スプライト画像->runAction(拡大アクション)」としてやれば、この命令が実行されたタイミングでスプライト画像が拡大アニメーション表示されます。

 

viewHitEffectメソッド内で使用しているアクションは下記になります。

・ScaleTo

拡大縮小アクション。createは第一引数に拡大縮小までの時間、第二引数に拡大縮小倍率を指定します。

「ScaleTo::create(0.1, 2.0)」とした場合は0.1秒かけて2倍の大きさにアニメーションします。

 

・FadeTo

透過率変更アクション。createは第一引数に拡大までの時間、第二引数に透過率(0~255)を指定します。

「FadeTo::create(0.1, 0)」とした場合は、0.1秒かけて透明になるアニメーションとなります。

 

・Spawn

複数のアクションを同時に実行するアクション。createは同時実行させたいアクションを複数指定します。viewHitEffectメソッド内では拡大と透明化を同時に行うアクションをcreateしています。

 

このSpawnを実行することでアニメーションを行えば良いように思いますが、これだけだと表示したヒットエフェクトが残り続けてしまいます。(※透明化を行っているので見かけはなくなったように見えますがしっかり残っています。透明化を行わないようにすればわかりやすいです。)

そこで、Spawnを行った後にはヒットエフェクトを削除したいのですが、削除するというアクションは存在しないので、メソッドを作成して削除してやる必要があります。そこで使用するのがラムダ式です。

 

 

ラムダ式

ラムダ式の詳細な説明は他のサイトに詳しく記載されているので、ここでは実際のプログラムの使い方を説明してきます。viewHitEffectメソッド内では以下の部分がラムダ式になります。

    auto removeHitEffect = CallFunc::create([hitEffect](){
        hitEffect->removeFromParent();
    });

 

このように記述することで、アクションと同じように扱う事ができるようになります。実行部分は「hitEffect->removeFromParent()」で、ヒットエフェクトの削除を行うラムダ式になります。

 

さて、話を戻して、spawnの後に続けてこのラムダ式を実行したいので、この「続けて行う」というアクションについて説明します。

・Sequence

複数のアクションを順番に実行するアクション。createは順次実行させたいアクションを複数指定します。

 

ヒットエフェクトを削除するラムダ式とSequenceを用意することで準備は整いました。アクションの実行を行いましょう。

 

 

アクションの実行

    // ヒットエフェクトの一連の流れ開始
    auto seq = Sequence::create(spawn, removeHitEffect, nullptr);
    hitEffect->runAction(seq);

 

とすることでエフェクト表示処理を行うことができます。

エフェクトこそ地味ですが、この「エフェクト表示 > 表示アニメーション完了に同期してエフェクト削除」という処理は、cocos2dxでプログラムを行う際には、エフェクトの表示方法に関わらず重要だと思います。

 

 

シミュレータの起動

それではシミュレータを起動してみましょう。ヒットエフェクトが表示されるようになったと思います。削除処理も行われているのでメモリリークの心配も無いですね。

だいぶゲームらしくなってきたと思いますが、まだプレイヤーが一方的にプレイするのみのゲームですね。次回はゲームのフェーズ(プレイヤーのターン、敵のターン)を実装していきましょう。

 

次回

第13回 「ゲームの状態(プレイヤーのターン 敵のターン、etc・・・)の実装」

 

 

 - ,

        

Message

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

  関連記事

cocos2dx
Cocos2d-x クライアント側の処理とデータ送信(Httpリクエスト)

この記事は「Cocos2d-x セーブデータをサーバに送信して保存する」の続きに …

ゲーム制作 Prain プレイン Cocos2d-x
ゲーム制作 Cocos2d-x関連 第17回 「タイトル画面の作成と画面遷移」

  この回ではタイトル画面と画面遷移を実装していきます。画面遷移が実装 …

楽ちん
Cocos2d-x アニメーションの画像追加を楽に行う方法

  この記事では、楽してアニメーション機能を利用する方法について紹介します。 & …

文字送り
Cocos2d-x テキストを1文字ずつ表示する文字送りのやり方

こんにちは。akiです。 この記事ではテキストを1文字ずつ表示する「文字送り」に …

パワーゲージ
ゲーム制作 Cocos2d-x関連 第10回 「パワーゲージによるボール移動距離の強弱付け」

コレは、・・・アレです。動くゲージをどこで止めるかによって、ボールの移動距離が変 …