フェードイン・フェードアウトを簡単に書けるFaderクラス

ゲームを作っているとある値を一定時間かけて変化させたいという場面が多くあります。 例えば、画面の明るさ(フェードイン・フェードアウト)、スコアの数値、HPゲージなど… こういった要素は一瞬で変化させるより、動きを与えた方が画面に高級感が出てきます。 しかしその都度値を管理するのはなかなかに面倒です。

こういう時はクラス化してしまうと便利になります。以下にその実装例を挙げました。 クラス定義が入っているので長いですが、最後のWinMain関数だけ見て下さい。

#include <DxLib.h>

class Timer{
public:
    Timer():time(0),count(0){};
    Timer(int time):time(time),count(0){};
    Timer(int time, int defaultCount):time(time),count(defaultCount){};
    ~Timer(){};
    void update(){ ++count; };
    void reset(){ count = 0; }
    void setTime(int time){ this->time = time; };
    void setTimeAndReset(int time){ this->time = time; count = 0; };
    int getCount() const { return count; };
    bool isPassed() const { return count >= time; };
private:
    int count;
    int time;
};

template<class T>
class Fader{
public:
    Fader():current(T()),goal(T()),velocity(T()){}
    Fader(const T& value):current(value),goal(value),velocity(T()){}
    const T& getCurrent() const { return current; }
    const T& getGoal() const { return goal; }
    void update(){
        if(timer.isPassed()){
            current = goal;
        }else{
            timer.update();
            current += velocity;
        }
    }

    operator T() const{
        return getCurrent();
    }

    const T& operator=(const T& value){
        set(value);
        return value;
    }
    T& operator=(T& value){
        set(value);
        return value;
    }
    void set(const T& value){
        current = goal = value;
        velocity = T();
        timer.setTimeAndReset(0);
    }
    void set(const T& value, int duration){
        if(value != goal){
            if(duration <= 0){
                return set(value);
            }
            goal = value;
            velocity = (goal - current) / duration;
            timer.setTimeAndReset(duration);
        }
    }
    bool isCompleted() const { return timer.isPassed(); }
private:
    T current;
    T goal;
    T velocity;
    Timer timer;
};

typedef Fader<double> NumberFader;


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){
    ChangeWindowMode(true);
    SetMainWindowText("FaderTest");
    SetGraphMode(640, 480, 32, 60);

    if(DxLib_Init() == -1){
        return -1;
    }

    SetDrawScreen(DX_SCREEN_BACK);

    NumberFader brightness = 0;
    // 明るさを240フレーム(4秒)かけて最大(255)にする
    brightness.set(255, 240 /*frames*/);

    while(ProcessMessage() == 0){
        ClearDrawScreen();
        DrawBox(0, 0, 640, 480, GetColor(brightness, brightness, brightness), true);
        brightness.update();
        ScreenFlip();
    }

    DxLib_End();
    return 0;
}

これだけです。明るさを定数にするのと比べてもほとんどコードを増やさずにフェードを実現できました。 なかなか便利ではないでしょうか?