0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

エフェクト取り扱い説明書

Last updated at Posted at 2019-12-16

はじめに

この記事はC++を学び始めたくらいの人を対象にした、ゲーム制作でのエフェクトの取り扱いをまとめたものです。

エフェクトとは

ここで扱うエフェクトは、ある時発生して一定時間動いたあと消えるものを指す。
(例 : あるキーを押したら自機周辺に白い円が現れ、時間経過で膨張し、一定時間経過後消えるもの)

やりたいこと

毎フレーム各エフェクトの処理(円の半径を増やすなど)を実行し、一定時間が経過したかの判定を行い、経過していたらそのエフェクトを削除する必要がある。
各エフェクトで更新内容が違うので、仮想関数を利用して解決する。

基底クラス

そうと決まればさっさと基底クラスを作成してしまおう。
すべての要素に必要な変数は、消えるまでの時間(定数)と発生してからの時間である。
関数は、毎フレーム一度だけ呼ぶ更新用の関数(update関数)と、描画を行う関数である。
エフェクトの削除はupdate関数の返り値でbool型を返してきて行うことにする。
時間の更新のため、基底クラスのupdate関数の中身を作成してそれを実行するようにした。
これらを実装する。

class Effect {
protected:
    Effect(unsigned int deleteFrame) : 
        mDeleteFrame(deleteFrame),
        mFrame(0)
    {
    }
public:
    virtual ~Effect() = default;
private:
    //発生からのフレーム数
    unsigned int mFrame;

protected:
    //発生からのフレーム数
    unsigned int frame() {
        return mFrame;
    }

    //削除までのフレーム数
    const unsigned int mDeleteFrame;

public:
    //削除する時にtrueを返す
    virtual bool update() {
        mFrame++;
        return false;
    }

    virtual void draw() const = 0;
};

エフェクト管理クラス

この方式でエフェクトを作成すると、各エフェクトのupdate関数に加えて基底クラスのupdate関数も呼ぶ必要がある。
また、各エフェクトをvectorなどの何かしらの方法で管理する必要がある。
これらを管理するクラスを作成する。

class EffectManager {
public:
    EffectManager() {
        
    }

    ~EffectManager() {
        clear(); //下で定義
    }

private:
    std::vector<Effect*> mEffect;

public:
    void update() {
        auto itr = std::remove_if(mEffect.begin(), mEffect.end(),
            [](Effect *t){
                t->Effect::udpate();
                bool flag = t->update();
                if(flag) delete t;
                return flag;
            }
        );
        mEffect.erase(itr, mEffect.end());
    }

    void draw() const {
        for(const auto &i : mEffect) {
            i->draw();
        }
    }

    //要素を追加
    void add(Effect *effect) {
        mEffect.emplace_back(effect);
    }

    //エフェクト全消去
    void clear() {
        for(const auto &i : mEffect) {
            delete i;
        }
        mEffect.clear();
    }
};

あとは、このクラスのインスタンスを作成して毎フレームupdateとdraw関数を呼べばいい。
エフェクトを追加したいときにadd関数に生成したインスタンスのポインタを渡すと自動的に更新削除までやってくれる。

作成例

DxLibを用いて白い円が20フレーム膨張して消えるだけのエフェクトを作成する。

class WhiteCircle : public Effect {
public:
    WhiteCircle(int x, int y) : 
        Effect(20),
        x(x),
        y(y),
        r(0)
    {}

    virtual ~WhiteCircle() = default;

    virtual void update() override {
        r++;
    }
    virtual void draw() const override {
        DrawCircle(x, y, r, 0xffffff, FALSE);
    }

private:
    int x;
    int y;
    int r;
}

おわりに

仮想関数を用いてエフェクトを簡単に取り扱えるようにやってみました。
実際各エフェクトクラスの実装が簡単に書けて管理も考えなくていいので割と扱いやすいのかなと思います。
改善点が多いコードなので是非考えてみてください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?