手付けUIアニメーションのすすめ
始めまして。入社3年目のプログラマー J と申します。
キャッシュを考慮したコードを書いてみよう!を書いた人の同期です。
今回は、手付けで実装する簡単なUIのプログラムを紹介したいと思います。
UIを手付けで実装するメリットは、性能が低いハードでのFPS保持や、複雑・オシャレな動きをさせたいなどがあります。
デメリットとしては、プログラマーの工数が増えるのでスケジュールとの相談だったりです。
使用したライブラリはSiv3Dです。
お手軽にプログラムが書けるので個人的におススメです。
まずは四角形を1つ表示してみます。
// ---------------------------------------- include
# include <Siv3D.hpp>
// ---------------------------------------- function
void Main()
{
// ウィンドウのタイトルを設定する
Window::SetTitle(L"UI Sample");
while (System::Update())
{
Rect(Point(100, 100), 150, 50).draw({ 0, 255, 0, 255 });
}
}
次にUIに必要なインアニメ、アウトアニメ、待ちアニメを制御する処理を追加します。
// ---------------------------------------- include
# include <Siv3D.hpp>
// ---------------------------------------- enum
// 状態の種類
enum eState
{
eState_In, // インアニメ中
eState_Out, // アウトアニメ中
eState_Wait,// 待機アニメ中
eState_Num, // 最大値
};
// ---------------------------------------- static
// 現在の状態
static eState s_State = eState_Wait;
// 描画フラグ
static bool s_IsDisp = false;
// ---------------------------------------- function
// 描画関数
static void _Draw()
{
switch (s_State)
{
// インアニメ
case eState_In:
break;
// アウトアニメ
case eState_Out:
break;
// 待ちアニメ
case eState_Wait:
break;
}
Rect(Point(100, 100), 150, 50).draw({ 0, 255, 0, 255 });
}
// メイン関数
void Main()
{
// ウィンドウのタイトルを設定する
Window::SetTitle(L"UI Sample");
while (System::Update())
{
if (s_IsDisp)
{
_Draw();
}
}
}
状態の種類、現在の状態、描画フラグを定義し、更新処理をswitchで分けるようにしました。
このコードを実行すると s_IsDisp が false のためUI表示されません。
それでは、
・左クリックしたら状態を eState_In にしてUIを表示
・インアニメ中はα値を60フレームで0から255に変化
・右クリックしたら状態を eState_Out にする
・アウトアニメ中はα値を30フレームで255から0に変化してUIを非表示
となるように実装します。
// ---------------------------------------- include
# include <Siv3D.hpp>
// ---------------------------------------- enum
// 状態の種類
enum eState
{
eState_In, // インアニメ中
eState_Out, // アウトアニメ中
eState_Wait,// 待機アニメ中
eState_Num, // 最大値
};
// ---------------------------------------- static
static eState s_State = eState_Wait; // 現在の状態
static bool s_IsDisp = false; // 描画フラグ
static int s_Timer = 0; // アニメ用タイマー
// ---------------------------------------- const
static const int ALPHA_MAX = 255; // α値の最大値
static const int IN_ANIM_TIME = 60; // インアニメの時間
static const int OUT_ANIM_TIME = 30; // アウトアニメの時間
// ---------------------------------------- function
// 描画関数
static void _Draw()
{
int alpha = ALPHA_MAX; // α値
switch (s_State)
{
// インアニメ
case eState_In:
{
double rate = static_cast<double>(s_Timer) / IN_ANIM_TIME;
alpha = static_cast<int>(rate * ALPHA_MAX);
// アニメ終了チェック、終了したら待ちアニメ状態にする
if (++s_Timer >= IN_ANIM_TIME)
{
s_State = eState_Wait;
}
}
break;
// アウトアニメ
case eState_Out:
{
double rate = static_cast<double>(OUT_ANIM_TIME - s_Timer) / OUT_ANIM_TIME;
alpha = static_cast<int>(rate * ALPHA_MAX);
// アニメ終了チェック、終了したらUIを非表示にする
if (++s_Timer >= OUT_ANIM_TIME)
{
s_IsDisp = false;
}
}
break;
// 待ちアニメ
case eState_Wait:
// 何もしない
break;
}
Rect(Point(100, 100), 150, 50).draw({ 0, 255, 0, alpha });
}
// メイン関数
void Main()
{
// ウィンドウのタイトルを設定する
Window::SetTitle(L"UI Sample");
while (System::Update())
{
// 左クリック
if (Input::MouseL.clicked)
{
s_State = eState_In;
s_IsDisp = true;
s_Timer = 0;
}
// 右クリック
else if (Input::MouseR.clicked)
{
s_State = eState_Out;
s_IsDisp = true;
s_Timer = 0;
}
if (s_IsDisp)
{
_Draw();
}
}
}
特に難しいことはせず、最終的なパラメータに対してオフセットするような形です。
これで基本部分の実装はできました。
あとはアニメーションの補間にイージングを使用し、移動、拡縮、回転などを加えるとクオリティアップできます。
また、状態を増やすことでイン、アウトだけでなく、別の動きを追加することも簡単です。
最後に
やはり、手付けでアニメーションを実装するのは時間がかかるものの、見た目が良く、処理速度が速いので、時間があるときは是非お試しください。
それでは。