12. 変数と動き¶
時間の経過を使って変数を変化させてモーション(動き)を作る方法を学びます。
12.1 前フレームからの経過時間を調べる¶
Scene::DeltaTime()
は、前フレームからの経過時間(秒)を double
型で返します。モニタが 60Hz の場合は約 0.0166 です。
# include <Siv3D.hpp>
void Main()
{
while (System::Update())
{
ClearPrint();
// 60 Hz の場合, 1/60 秒(約 0.0166)
const double deltaTime = Scene::DeltaTime();
Print << deltaTime;
}
}
12.2 絵文字を動かす¶
メインループの繰り返しのたびに位置をずらすことで、移動のモーションができます。
# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.8, 0.9, 1.0 });
const Texture emoji{ U"☃️"_emoji };
// 移動速度(ピクセル / 秒)
const double velocity = 20;
// 絵文字の X 座標
double x = 100;
while (System::Update())
{
x += (Scene::DeltaTime() * velocity);
emoji.drawAt(x, 300);
}
}
12.3 絵文字を回転させる¶
メインループの繰り返しのたびに回転角度をずらすことで、回転のモーションができます。
# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.8, 0.9, 1.0 });
const Texture emoji{ U"🍣"_emoji };
// 回転速度(ラジアン / 秒)
const double angularVelocity = 90_deg;
// 回転角度
double angle = 0_deg;
while (System::Update())
{
angle += (Scene::DeltaTime() * angularVelocity);
emoji.rotated(angle).drawAt(400, 300);
}
}
12.4 図形の変数¶
Circle
型や Rect
, RectF
型の変数を作れます。
# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(Palette::White);
Circle circle{ 200, 200, 100 };
RectF rect{ 400, 300, 300, 200 };
while (System::Update())
{
circle.draw(Palette::Orange);
circle.drawFrame(2, 2, Palette::Red);
rect.draw(ColorF{ 0.5 });
RectF{ rect.x, rect.y, (rect.w * 0.5), rect.h }.draw(ColorF{ 0.3, 0.9, 0.6 });
rect.drawFrame(4, 4, ColorF{ 0.2 });
}
}
12.5 図形を動かす¶
図形のメンバ変数を時間の経過に応じて変更することで、図形の位置や大きさをアニメーションできます。
# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.8, 0.9, 1.0 });
Circle circle{ 200, 300, 0 };
RectF rect{ 300, 200, 300, 200 };
while (System::Update())
{
double deltaTime = Scene::DeltaTime();
circle.r += (deltaTime * 20);
rect.x += (deltaTime * 10);
circle.draw();
rect.draw(ColorF{ 0.5 });
}
}
12.6 経過時間を蓄積する¶
前フレームからの経過時間を蓄積することで、時間を測定できます。
# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.8, 0.9, 1.0 });
const Font font{ FontMethod::MSDF, 48 };
// 経過時間の蓄積(秒)
double accumulatedTime = 0.0;
while (System::Update())
{
accumulatedTime += Scene::DeltaTime();
font(U"経過時間: {:.2f}"_fmt(accumulatedTime)).draw(40, 20, 20, Palette::Black);
}
}
12.7 残り時間をカウントダウンする¶
残り時間から Scene::DeltaTime()
の値を引いていくことで、時間のカウントダウンができます。
# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.8, 0.9, 1.0 });
const Font font{ FontMethod::MSDF, 48 };
// 残り時間(秒)
double timeLeft = 5.0;
while (System::Update())
{
timeLeft -= Scene::DeltaTime();
if (0.0 < timeLeft)
{
font(U"残り時間: {:.2f}"_fmt(timeLeft)).draw(40, 20, 20, Palette::Black);
}
else
{
font(U"ゲームオーバー").draw(40, 20, 20, Palette::Black);
}
}
}
12.8 一定時間ごとにイベントを発生させる¶
12.6 を応用すると、一定時間ごとにイベントを発生させることができます。蓄積時間が一定時間を超えたらイベントを発生させ、蓄積時間をその時間だけ減らします。
次のコードでは、3 秒ごとに Print << U"Hello!"
を実行します。
# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.8, 0.9, 1.0 });
const Font font{ FontMethod::MSDF, 48 };
// 周期(秒)
const double interval = 3.0;
// 蓄積時間(秒)
double accumulatedTime = 0.0;
while (System::Update())
{
accumulatedTime += Scene::DeltaTime();
font(U"accumulatedTime: {:.2f}"_fmt(accumulatedTime)).draw(40, 200, 20, Palette::Black);
// 蓄積時間が一定時間を超えたら
if (interval <= accumulatedTime)
{
Print << U"Hello!";
// 蓄積時間からマイナス
accumulatedTime -= interval;
}
}
}
蓄積時間を完全に 0 にリセットしない理由
蓄積時間を accumulatedTime = 0.0
でリセットしないのは、例えば頻度が 3 秒ごとで、蓄積時間が 3.02 秒だった場合、イベントを発生させたあとに、余りの 0.02 秒を次のイベントの蓄積時間に使うためです。これを無視してしまうと、イベントの発生頻度が 3 秒よりも長くなってしまいます。
振り返りチェックリスト¶
-
Scene::DeltaTime()
で前フレームからの経過時間(秒)を取得できることを学んだ - 経過時間を使って絵文字を動かす方法を学んだ
- 経過時間を使って図形を動かす方法を学んだ
- 経過時間を蓄積して時間を測定する方法を学んだ
- 経過時間を利用して残り時間をカウントダウンする方法を学んだ
- 経過時間の蓄積を利用して、一定時間ごとにイベントを発生させる方法を学んだ