C++
VisualC++

パラメーター用のクラス

経緯とか書くと長くなるのでまずはコードから

PossibleChangeStatus.hpp
#ifndef __POSSIBLECHANGESTATUS_HPP__
#define __POSSIBLECHANGESTATUS_HPP__
#ifdef _MINWINDEF_ // Windows.h等がこのヘッダーより先にincludeされるとダメなのでundefする
#undef max
#undef min
#endif
#include <type_traits>
#include <algorithm>

inline float ChangeTwoDigits(const double Data) {
    return static_cast<float>(static_cast<int>((Data + 0.005) * 100)) / 100;
}

//C++17
template<typename T>
const T& clamp(const T& v, const T& lo, const T& hi) {
    return assert( !comp(hi, lo) ),
        (v < lo) ? lo : (hi < v) ? hi : v;
}

template<class T> class PossibleChangeStatus {
private:
    T MinStatus;
public:
    //public member variable
    T CurrentStatus, MaxStatus;

    PossibleChangeStatus() = default;
    PossibleChangeStatus(const PossibleChangeStatus&) = default;
    PossibleChangeStatus& operator=(const PossibleChangeStatus&) = default;
    PossibleChangeStatus(const T Max) : PossibleChangeStatus(Max, Max) {}
    PossibleChangeStatus(const T Current, const T Max, const T Min = 0)
        : MinStatus(Min), CurrentStatus(Current), MaxStatus(Max) {}


    //public member function
    PossibleChangeStatus operator+(const T Num) {
        return {
            clamp(this->CurrentStatus + Num, this->MinStatus, this->MaxStatus),
            this->MaxStatus, this->MinStatus
        };
    }
    PossibleChangeStatus operator-(const T Num) {
        return {
            clamp(this->CurrentStatus - Num, this->MinStatus, this->MaxStatus),
            this->MaxStatus, this->MinStatus
        };
    }
    PossibleChangeStatus operator*(const T Num) {
        return {
            clamp(this->CurrentStatus * Num, this->MinStatus, this->MaxStatus),
            this->MaxStatus, this->MinStatus
        };
    }
    PossibleChangeStatus operator/(const T Num) {
        return {
            clamp(this->CurrentStatus / Num, this->MinStatus, this->MaxStatus),
            this->MaxStatus, this->MinStatus
        };
    }
    PossibleChangeStatus& operator += (const T Num) {
        this->CurrentStatus = clamp(this->CurrentStatus + Num, this->MinStatus, this->MaxStatus);
        return *this;
    }
    PossibleChangeStatus& operator -= (const T Num) {
        this->CurrentStatus = clamp(this->CurrentStatus - Num, this->MinStatus, this->MaxStatus);
        return *this;
    }
    PossibleChangeStatus& operator *= (const T Num) {
        this->CurrentStatus = clamp(this->CurrentStatus * Num, this->MinStatus, this->MaxStatus);
        return *this;
    }
    PossibleChangeStatus& operator /= (const T Num) {
        this->CurrentStatus = clamp(this->CurrentStatus / Num, this->MinStatus, this->MaxStatus);
        return *this;
    }
    PossibleChangeStatus& operator++() {
        this->CurrentStatus = std::min(this->CurrentStatus + 1, this->MaxStatus);
        return *this;
    }
    PossibleChangeStatus operator++(int) {
        const auto re = *this;
        ++(*this);
        return re;
    }
    PossibleChangeStatus& operator--() {
        this->CurrentStatus = std::max(this->CurrentStatus - 1, this->MinStatus);
        return *this;
    }
    PossibleChangeStatus operator--(int) {
        const auto re = *this;
        --(*this);
        return re;
    }
    T& operator * () { return this->CurrentStatus; }
    const T& operator * () const { return this->CurrentStatus; }
    T& get() { return this->CurrentStatus; }
    const T& get() const { return this->CurrentStatus; }
    bool operator< (const T CompareNum) const { return this->CurrentStatus < CompareNum; }
    bool operator<= (const T CompareNum) const { return this->CurrentStatus <= CompareNum; }
    bool operator> (const T CompareNum) const { return this->CurrentStatus > CompareNum; }
    bool operator>= (const T CompareNum) const { return this->CurrentStatus >= CompareNum; }
    bool IsMin() const { return this->CurrentStatus == this->MinStatus; }
    bool IsMax() const { return this->CurrentStatus == this->MaxStatus; }
    float GetProportion() const { return ChangeTwoDigits(static_cast<double>(this->CurrentStatus) / static_cast<double>(this->MaxStatus - this->MinStatus)); }
};
template<typename T>
inline bool operator==(T l, const PossibleChangeStatus<T>& r) { return l == r.CurrentStatus; }
template<typename T>
inline bool operator==(const PossibleChangeStatus<T>& l, T r) { return r == l; }
template<typename T>
inline bool operator!=(T l, const PossibleChangeStatus<T>& r) { return !(l == r); }
template<typename T>
inline bool operator!=(const PossibleChangeStatus<T>& l, T r) { return r != l; }

#endif

このクラス作った環境がVisual Studio Professional 2013だった関係もありますが、一応constexprの使用は控えてありますので、C++11以前でも一応使える(?)ようになってます。(yumetodo氏みたく企画書読んだり大学の単位を捧げたりするほどC++やってないのでC++いくつまで使えるのかは知りません)

さて、作った経緯なんですが、現在公開中の未完成作品モンスター討伐ゲーム アンチ核家族化のパラメーターを管理するにあたり、Statusというクラスがこんなことになってまして…

Status.h
#include <string>

class Status {
public:
    Status(std::vector<status_data> arr, int i, bool is_player_setting);
    std::string name;
    int hp, max_hp, mp, max_mp, attack, defence, magic_attack, magic_defence, speed, graph_handle;
    bool is_male;
};

変数定義もちょっと多いし、計算部分に毎度毎度std::maxとstd::min書くのがめちゃくちゃめんどくなりまして…。
特に敵からの範囲攻撃、味方による範囲回復になると各キャラのHP変更するだけで3個も書かないといけなくて…。

まあそれがあまりにめんどくて、このクラスを作ったわけです。
これならGetProportion関数使えばHPゲージの実装も楽ですし、Minimize関数使えば死亡判定可能ですし、Less関数使えばパラメーター表示色変更も実装できちゃいます。

追記1

このクラスを他のキャラクター情報管理に使用するクラスと共にMITライセンスでGitHubに公開開始しました。
当該リポジトリはこちら
2017年8月23日現在、動作を完全に保証できるコンパイル環境は以下の通りです。

  • Microsoft Visual Studio 2013(PossibleChangeStatusクラスのみ)
  • Microsoft Visual Studio 2015
  • Microsoft Visual Studio 2017