経緯とか書くと長くなるのでまずはコードから
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