Skip to content

Instantly share code, notes, and snippets.

@Pctg-x8
Created January 29, 2015 18:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Pctg-x8/91951196fb4509f80941 to your computer and use it in GitHub Desktop.
Save Pctg-x8/91951196fb4509f80941 to your computer and use it in GitHub Desktop.
AnimationManager: classes which provide simply easing animations on Siv3D(January 2015)
#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