Cocos2d-xでFF5風のダメージを再現する

Cocos2d-x(3.x系)で、FF5風のダメージ表示のエフェクトを再現してみました。

制作環境は以下の通りです。

  • Cocos2d-x 3.14.1
  • Windows10上でWin32プロジェクトにて確認

参考にした動画

www.youtube.com

実装した結果

微妙に画像がつぶれているので見づらい場合は拡大してください。

説明

前回のCocos2d-xでロマンシングサ・ガ3風のダメージ表示を再現するで実装したクラスを流用してアクションの部分だけ書き換えを行います。

ダメージ表示の仕様ですが

  • 最上位桁から最下位桁の順に表示される
  • 表示された順に数字が飛び上がる
  • 着地したあと少しだけバウンドする

となります。ロマサガと違ってシンプルに出来ています。

ヘッダー側

前回記事のものとほぼ動揺で、Nodeを継承した表示用のクラスをこんな感じで用意します。

#pragma once
#pragma execution_character_set("utf-8")

#include "cocos2d.h"

// ダメージ表示を表します。
class DmgEffectFF5 : public cocos2d::Node
{
    DmgEffectFF5();

    // 各桁を表すラベルを作成する
    void createLabels(std::string dmg);

    // 最後に自殺する動作を設定する
    void setupCleanupAction(std::string dmg, float dulation);

    // 生成したラベルを取り出す
    std::vector<Node*> getLabels(std::string dmg);

public:

    // リソースを解放してオブジェクトを破棄する
    ~DmgEffectFF5();

    // いつもの
    virtual bool init() override;
    
    // いつもの
    static DmgEffectFF5* create();

    // 指定した数値でダメージエフェクトを開始する
    void showEffect(int dmg);

    // 全てのActionが終了した時の処理
    void remove();
};

実装側(抜粋)

上記ヘッダーに肉付けしていきます。表示状態は管理しないので、全部終了したら自分で自分を消去するように仕込んでおきます。(そのためにNodeを継承しています)

#include "DmgEffectFF5.h"

using namespace std;
using namespace cocos2d;

DmgEffectFF5::DmgEffectFF5()
{
    // nop
}

void DmgEffectFF5::createLabels(string dmg)
{
    for (int i = 0; i < dmg.length(); i++)
    {
        // BABARAGEOさんからお借りしたBABARAGEOフォント
        // http://babarageo.com/cgi/wp/ja/notes/babarageo-font.html
        auto _label = Label::create(std::string{ dmg[i] }, "fonts/babarageo3.ttf", 10);
        _label->setTag(i);
        this->addChild(_label);
    }
}

void DmgEffectFF5::setupCleanupAction(string dmg, float dulation)
{
    // エフェクトが全部終わったら自殺する設定
    Node* last = this->getChildByTag(dmg.length()-1);
    last->runAction(Sequence::create(DelayTime::create(dulation + 0.7f),
        CallFunc::create(CC_CALLBACK_0(DmgEffectFF5::remove, this)), nullptr));
}

std::vector<Node*> DmgEffectFF5::getLabels(string dmg)
{
    vector<Node*> labelList;
    for (int i = 0; i < dmg.length(); i++)
    {
        labelList.push_back(this->getChildByTag(i));
    }

    return labelList;
}

DmgEffectFF5::~DmgEffectFF5()
{
    this->remove();
}

bool DmgEffectFF5::init() { /* 省略 */ }

DmgEffectFF5* DmgEffectFF5::create() { /* 省略 */ }

void DmgEffectFF5::showEffect(int dmg)
{
    string dmgStr = to_string(dmg);

    this->createLabels(dmgStr);

    // 数字がジャンプする動作の設定
    int i = 0;
    float dulation = 0.0f;
    for (Node* _label : this->getLabels(dmgStr))
    {
        _label->setPosition(Vec2(i * 14, 0));

        auto dylayAction = DelayTime::create(i * 0.04);
        auto jumpAction1 = JumpBy::create(0.25f, Vec2(0, -10), 28, 1);
        auto jumpAction2 = JumpBy::create(0.1f, Vec2(0, 0), 12, 1);
        _label->runAction(Sequence::create(dylayAction, jumpAction1, jumpAction2, nullptr));

        i++;
    }

    this->setupCleanupAction(dmgStr, dulation);
}

void DmgEffectFF5::remove()
{
    this->removeAllChildrenWithCleanup(true);
    this->removeFromParentAndCleanup(true);
}

利用側コード

使用する時は、タッチ時に少し右側に表示しています。

bool HelloWorld::init()
{
    // ...省略...

    srand((unsigned int)time(nullptr));

    auto listner = EventListenerTouchOneByOne::create();

    listner->onTouchBegan = [this](Touch* touch, Event* event)
    {
        DmgEffectFF5* effect = DmgEffectFF5::create();
        effect->setPosition(Vec2(touch->getLocation().x + 30, touch->getLocation().y));
        effect->showEffect(rand() % 9999);
        this->addChild(effect);

        return true;
    };

    this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listner, this);

    return true;
}

処理手順ですが

  1. ダメージを数字で取る
  2. 各桁に対応する文字をラベルで生成する
  3. ラベルにジャンプアクション(JunbBy)を設定する(この時、最上位桁から少しづつ表示を遅らせる)

となります。その場でジャンプするだけなのでアクションの事を理解していれば割と簡単に実装できると思います。

関連記事

Cocos2d-xでロマンシングサ・ガ3風のダメージ表示を再現する Cocos2d-xでFF5風のダメージを再現する(この記事)