Created
January 29, 2015 18:43
-
-
Save Pctg-x8/91951196fb4509f80941 to your computer and use it in GitHub Desktop.
AnimationManager: classes which provide simply easing animations on Siv3D(January 2015)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Siv3D.hpp> | |
/// AnimationManagerおよび関係クラス /// | |
/// AnimationManager: Siv3D January 2015より追加されたEasing名前空間のものをより扱いやすくする補助クラスです。 | |
class IAnimationParameter | |
{ | |
// テンプレートの情報を消すための下駄 | |
friend class AnimationManager; | |
virtual void process(double t) = 0; | |
public: | |
virtual ~IAnimationParameter(){} | |
}; | |
#pragma warning(push) | |
// 代入演算子を作れないとかのエラーが出るため抑制(たぶん参照のせい) | |
#pragma warning(disable: 4512) | |
template<typename TargetT> struct AnimationParameter : public IAnimationParameter | |
{ | |
// 実体 | |
// 一つのアニメーションを表す(startTimeからendTimeの間でeaseParameterをstartParamからendParamにeasingFunctionを使って動かす) | |
TargetT& easeParameter; | |
TargetT startParam, endParam; | |
std::function<double(double)> easingFunction; | |
double startTime, endTime; | |
AnimationParameter(TargetT& epRef, TargetT sp, TargetT ep, std::function<double(double)> ef, double st, double et) | |
: easeParameter(epRef), startParam(sp), endParam(ep), easingFunction(ef), startTime(st), endTime(et) | |
{ } | |
AnimationParameter(const AnimationParameter<TargetT>& base) | |
: easeParameter(base.easeParameter), startParam(base.startParam), endParam(base.endParam), | |
easingFunction(base.easingFunction), startTime(base.startTime), endTime(base.endTime) | |
{ } | |
virtual ~AnimationParameter(){} | |
virtual void process(double t) | |
{ | |
// 実際の操作(IAnimationParameterはパラメータ情報にアクセス出来ないので実体側に処理を移す) | |
if (startTime <= t && t < endTime) | |
{ | |
easeParameter = Lerp(startParam, endParam, easingFunction((t - startTime) / (endTime - startTime))); | |
} | |
} | |
}; | |
// EaseOut, EaseInOutの引数固定を行うサポート関数(デフォルトの動作はEaseIn) | |
inline std::function<double(double)> EaseOutWrapper(std::function<double(double)> baseFunc) | |
{ | |
return std::bind(Easing::EaseOut, baseFunc, std::placeholders::_1); | |
} | |
inline std::function<double(double)> EaseInOutWrapper(std::function<double(double)> baseFunc) | |
{ | |
return std::bind(Easing::EaseInOut, baseFunc, std::placeholders::_1); | |
} | |
class AnimationManager | |
{ | |
// AnimationManager本体 | |
// タイマーを勝手に管理する | |
TimerMillisec msTimer; | |
std::vector<IAnimationParameter*> animList; | |
public: | |
// constructor | |
AnimationManager() | |
{ | |
msTimer.reset(); | |
} | |
// destructor(ポインタなので自分で開放する) | |
~AnimationManager() | |
{ | |
msTimer.pause(); | |
for (auto p : animList) delete p; | |
} | |
// アニメーションを追加(easeParameterには動かしたい変数を指定する) | |
// startParamからendParamまでをEasingFunctionで補完して動かしてくれる | |
template<typename TargetT> | |
void addAnimation(TargetT& easeParameter, TargetT startParam, TargetT endParam, std::function<double(double e)> EasingFunction, double startTime = 0, double endTime = 1000) | |
{ | |
// unit: px/ms | |
animList.push_back(new AnimationParameter<TargetT>(easeParameter, startParam, endParam, EasingFunction, startTime, endTime)); | |
} | |
// アニメーションを開始 | |
void startAnimation() | |
{ | |
msTimer.start(); | |
} | |
// アニメーションを一時停止 | |
void pauseAnimation() | |
{ | |
msTimer.pause(); | |
} | |
// アニメーションをリセット | |
void resetAnimation(){ msTimer.reset(); } | |
// アニメーションを再スタート | |
void restartAnimation(){ msTimer.restart(); } | |
// アニメーションの更新(これを呼ばないといつまで経っても動かない) | |
void updateAnimation() | |
{ | |
auto currentTime = msTimer.elapsed(); | |
// とりあえずforeachで回す(animListのサイズ(キーフレーム量)が多くなると遅くなる) | |
// (animListをパラメータごとに予め開始時間でソートしておいて、次行うものだけを見る、とかの実装をしたほうが賢いし早いと思う) | |
for (auto a : animList) | |
{ | |
a->process(currentTime); | |
} | |
} | |
}; | |
#pragma warning(pop) | |
/// ここまでAnimationManager /// | |
// 使用例 | |
void Main() | |
{ | |
AnimationManager am; | |
Vec2 rectPos; | |
double round; | |
Color col; | |
// Vec2(構造体)の要素をアニメーション | |
am.addAnimation(rectPos.x, 0.0, 400.0, EaseInOutWrapper(Easing::Quad), 0, 2000); | |
am.addAnimation(rectPos.y, 0.0, 100.0, Easing::Quint, 0, 500); | |
am.addAnimation(rectPos.y, 100.0, 0.0, EaseOutWrapper(Easing::Quint), 500, 1000); | |
am.addAnimation(rectPos.y, 0.0, 100.0, Easing::Quint, 1000, 1500); | |
am.addAnimation(rectPos.y, 100.0, 0.0, EaseOutWrapper(Easing::Quint), 1500, 2000); | |
// ローカル変数をアニメーション | |
am.addAnimation(round, 0.0, 720.0, EaseInOutWrapper(Easing::Quart), 0, 2000); | |
// 色をアニメーション | |
am.addAnimation(col, Color(255, 255, 255), Color(255, 0, 0), Easing::Circ, 0, 1000); | |
am.addAnimation(col, Color(255, 0, 0), Color(0, 255, 0), EaseOutWrapper(Easing::Circ), 1000, 2000); | |
am.startAnimation(); | |
while (System::Update()) | |
{ | |
if (Key('R').pressed) am.restartAnimation(); | |
if (Key('P').pressed) am.pauseAnimation(); | |
if (Key('S').pressed) am.startAnimation(); | |
am.updateAnimation(); | |
RectF(rectPos, Vec2(48.0, 48.0)).rotatedAt(Vec2(rectPos.x + 24.0, rectPos.y + 24.0), Math::Radians(round)).draw(col); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment