OpenSiv3D（0.6.3）で5行コピペでフレームレート固定（60FPS）を作る

###### ここはとりあえず的に作ったもので、別ページに改良バージョンがあります。こちらをご使用ください。
https://qiita.com/loppta/items/d0672fb68279e110ebaa

以下の改良されています。

::: note alert
改良前 ・ソースコードにあれこれ追加で部品化や汎用性が考えられていない。
改良前 ・単純に1/60秒待っているので処理落ちしやすい。正確な時間処理はしていない
:::
:::note info
改良後 ・ヘッダーファイル追加で変更箇所がかなり少なくなる、主コードを圧迫しない
改良後 ・必ず６０FPSで計算するようになり、かなり計算処理落ちは無くなる
※状況により描画しないで計算のつじつまを合わせる方法（市販ゲームで行っている昔からある方法）
:::
steamで販売のものを作るとかなら、話は別ですが、自分用のちょっとしたミニゲームを作るくらいなら、これで十分と考えてその場で作ったものです。
上記リンク先はやるべきだとは普通に考えていました。
XNAライブラリでは標準装備だったので気持ちは引っ張られてはいましたが、
まあいっか、という感じで保留していました。
~~誰かこの面倒な処理を続けて作ってくれという他力本願の願いが本音なところ~~
~~何か問題が起きたら、改良しよう~~
- - -
以下、旧記事

OpenSiv3D(0.6.3)では、下記命令はありません

```:CPP
Graphics::SetTargetFrameRateHz(60);   // 1秒間60回 画面を書き換える設定にする

```

あれ？ OpenSiv0.4.3 ではあったのに？？と思って手短に作りましたが、まあいいや、で何か月か放置していました。
で、まあ嫌がっている人がほかに聞いたらけっこういらっしゃったので、こちらにＵＰする形になりました。

昔のPCでは、ライブラリ系では基本は60FPS（フレームパーセコンド、1秒間に画面を書き換える回数）
これには近年のPCでは困ったことがあります。
昔のコンピュータでは、フルスクリーンのゲームを作ると、何も設定せずとも６０FPSになります。
家庭用ゲームと同じ設定です。（1部ヨーロッパの除く）

しかし、最近のＰＣではＦＰＳが60以外も144とかも多く、この描画回数が多くなると、
動きが早くなってしまい、

人にプログラムを渡すと、

<font color="Red">Ａ</font>君  >>>> <B>プログラムを渡す</B> >>>  <font color="Red">Ｂ</font>君      <B> 動きが早すぎになってしまうよ！！</B>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76087/b70bc76e-3d3c-c0e4-e117-748aa2f5e33e.png)B君


Ａ君ＰＣ＝６０ＦＰＳのＰＣ
B君ＰＣ＝１４４ＦＰＳのＰＣ

初心者はそんなことは分かりません。



描画ループの <B>while (System::Update())</B> の上に3行を書きます。<font color="Red"><B>3行コピペ</B></font>

```cpp:System&#58;&#58;Update()の上の行に貼り付ける内容
	int FPS = 60; // 1秒間に1画面を書き換える回数
	Stopwatch sw;	//FPS60
	sw.start();	//FPS60

	while (System::Update()) // ↑に追加 
	{


```

描画ループの while (System::Update())のループの最下 **`}`** の上に２行を追加します。<font color="Red"><B>2行コピペ</B></font>


```cpp:System&#58;&#58;Update(){の上の行に貼り付ける内容
		while (sw.msF() < 1000.0 / FPS);	//1/60秒経過するまでループ
		sw.restart();	//FPS60  ストップウォッチをリスタート
	}
```

まあ、こんな感じで、<font color="Red"><B>たった5行コピペ</B></font>すればOKです。

これだと動作が分からないので下記にサンプルコードを載せます。

実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76087/c7f93cc3-3325-f55a-5c0d-bf16ef62f1e1.png)

Windowタイトルで60FPS表示されているのが分かります。
この設定をしないと使用しているPCではFPSが144くらいだったと思います。

サンプルコード


```cpp:60fpsMain.cpp
# include <Siv3D.hpp> // OpenSiv3D v0.6.3

/*
	要望があれば改良記事を書きます。
*/

void Main()
{
	// 背景の色を設定 | Set background color
	Window::Resize(DisplayResolution::HD_1280x720);
	Scene::Resize(DisplayResolution::HD_1280x720);
	Scene::SetBackground(ColorF{ 0.8, 0.9, 1.0 });
	Graphics::SetVSyncEnabled(false);

	// 通常のフォントを作成 | Create a new font
	const Font font{ 60 };

	// 絵文字用フォントを作成 | Create a new emoji font
	const Font emojiFont{ 60, Typeface::ColorEmoji };

	// `font` が絵文字用フォントも使えるようにする | Set emojiFont as a fallback
	font.addFallback(emojiFont);

	// 画像ファイルからテクスチャを作成 | Create a texture from an image file
	const Texture texture{ U"example/windmill.png" };
	const Texture s3kun{ U"example/siv3d-kun.png" };
	int x = 0;

	// 絵文字からテクスチャを作成 | Create a texture from an emoji
	const Texture emoji{ U"🐈"_emoji };


	// 絵文字を描画する座標 | Coordinates of the emoji
	Vec2 emojiPos{ 300, 150 };

	// テキストを画面にデバッグ出力 | Print a text
	Print << U"Push [A] key";

	Rect rect(100, 100, 200, 50);

	int FPS = 60; // 1秒間に1画面を書き換える回数
	Stopwatch sw;	//FPS60
	sw.start();	//FPS60

	while (System::Update()) // ↑に追加 
	{
		// テクスチャを描く | Draw a texture
		texture.draw(200, 200);

		// テキストを画面の中心に描く | Put a text in the middle of the screen
		font(U"Hello, Siv3D!🚀").drawAt(Scene::Center(), Palette::Black);

		// サイズをアニメーションさせて絵文字を描く | Draw a texture with animated size
		emoji.resized(100 + Periodic::Sine0_1(1s) * 20).drawAt(emojiPos);

		// マウスカーソルに追随する半透明な円を描く | Draw a red transparent circle that follows the mouse cursor
		Circle{ Cursor::Pos(), 40 }.draw(ColorF{ 1, 0, 0, 0.5 });

		// もし [A] キーが押されたら | When [A] key is down
		if (KeyA.down())
		{
			// 選択肢からランダムに選ばれたメッセージをデバッグ表示 | Print a randomly selected text
			Print << Sample({ U"Hello!", U"こんにちは", U"你好", U"안녕하세요?" });
		}

		// もし [Button] が押されたら | When [Button] is pushed
		if (SimpleGUI::Button(U"Button", Vec2{ 640, 40 }))
		{
			// 画面内のランダムな場所に座標を移動
			// Move the coordinates to a random position in the screen
			emojiPos = RandomVec2(Scene::Rect());
		}
		x += 2;
		x %= DisplayResolution::HD_1280x720.x + s3kun.width() * 2;
		s3kun.drawAt( x-s3kun.width() ,Scene::Center().y);

		font(U"1 frame time:{:.5f}"_fmt(Scene::DeltaTime()))
			.drawAt(Scene::Center().x,Scene::Height()-font.fontSize()*2,Palette::Black);
		font(U"FPS:{:.2f}"_fmt(1/Scene::DeltaTime()))
			.drawAt(Scene::Center().x,Scene::Height()-font.fontSize()*1,Palette::Black);

		auto rr=rect.rotated(Scene::Time());
		auto r0=rect.rotated(0);
		bool tt=rr.intersects(Rect(100,100,300,300));
		bool tt0=Rect(100,100,300,300).intersects(rr);
		rect.rotated((Scene::Time())).draw(Palette::Cadetblue);


		while (sw.msF() < 1000.0 / FPS);	//1/60秒経過するまでループ
		sw.restart();	// ストップウォッチをリスタート
	}
}


```

VisualStudio2019使用 OpenSIv3D 0.6.3



FPS固定だと処理落ちすると動きがゆっくりになります。





これの解決方法として家庭用ゲームでは一般的なのは <b>フレームスキップ機能</b> です。
３Dゲームでは処理落ちは頻繁にあります。
例えばヘリに搭乗して空高く飛ぶと、ポリゴンめいっぱいの街並みが表示されたりする場面です。
（レインボーシックスベガス）
コマ落ちしているのが分かると思います。
処理落ちしたら、その時のフレームは描画をしないです。
処理速度で最も大きいのはだいたい描画です。
状況により、描画をせずにして時間経過における座標変化速度を維持しようとするのです。

PS3の3Dゲームとかが分かりやすいでしょうか。表示物が多いとすぐコマ落ちするんで。

マイクロソフトのXNAライブラリは描画ループで標準装備されていました。

次回は要望があればOpenSiv3Dでそれの実装コードの記事を載せたいと思います。数行追加すればできますね。

ついでにゲームでよくある一時停止についてもやるかも？

分かりにくい点などご指摘いただければ修正いたします。