ここはとりあえず的に作ったもので、別ページに改良バージョンがあります。こちらをご使用ください。
以下の改良されています。
改良前 ・ソースコードにあれこれ追加で部品化や汎用性が考えられていない。
改良前 ・単純に1/60秒待っているので処理落ちしやすい。正確な時間処理はしていない
改良後 ・ヘッダーファイル追加で変更箇所がかなり少なくなる、主コードを圧迫しない
改良後 ・必ず60FPSで計算するようになり、かなり計算処理落ちは無くなる
※状況により描画しないで計算のつじつまを合わせる方法(市販ゲームで行っている昔からある方法)
steamで販売のものを作るとかなら、話は別ですが、自分用のちょっとしたミニゲームを作るくらいなら、これで十分と考えてその場で作ったものです。
上記リンク先はやるべきだとは普通に考えていました。
XNAライブラリでは標準装備だったので気持ちは引っ張られてはいましたが、
まあいっか、という感じで保留していました。
誰かこの面倒な処理を続けて作ってくれという他力本願の願いが本音なところ
何か問題が起きたら、改良しよう
以下、旧記事
OpenSiv3D(0.6.3)では、下記命令はありません
Graphics::SetTargetFrameRateHz(60); // 1秒間60回 画面を書き換える設定にする
あれ? OpenSiv0.4.3 ではあったのに??と思って手短に作りましたが、まあいいや、で何か月か放置していました。
で、まあ嫌がっている人がほかに聞いたらけっこういらっしゃったので、こちらにUPする形になりました。
昔のPCでは、ライブラリ系では基本は60FPS(フレームパーセコンド、1秒間に画面を書き換える回数)
これには近年のPCでは困ったことがあります。
昔のコンピュータでは、フルスクリーンのゲームを作ると、何も設定せずとも60FPSになります。
家庭用ゲームと同じ設定です。(1部ヨーロッパの除く)
しかし、最近のPCではFPSが60以外も144とかも多く、この描画回数が多くなると、
動きが早くなってしまい、
人にプログラムを渡すと、
A君 >>>> プログラムを渡す >>> B君 動きが早すぎになってしまうよ!!
A君PC=60FPSのPC
B君PC=144FPSのPC
初心者はそんなことは分かりません。
描画ループの while (System::Update()) の上に3行を書きます。3行コピペ
int FPS = 60; // 1秒間に1画面を書き換える回数
Stopwatch sw; //FPS60
sw.start(); //FPS60
while (System::Update()) // ↑に追加
{
描画ループの while (System::Update())のループの最下 }
の上に2行を追加します。2行コピペ
while (sw.msF() < 1000.0 / FPS); //1/60秒経過するまでループ
sw.restart(); //FPS60 ストップウォッチをリスタート
}
まあ、こんな感じで、たった5行コピペすればOKです。
これだと動作が分からないので下記にサンプルコードを載せます。
Windowタイトルで60FPS表示されているのが分かります。
この設定をしないと使用しているPCではFPSが144くらいだったと思います。
サンプルコード
# 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固定だと処理落ちすると動きがゆっくりになります。
これの解決方法として家庭用ゲームでは一般的なのは フレームスキップ機能 です。
3Dゲームでは処理落ちは頻繁にあります。
例えばヘリに搭乗して空高く飛ぶと、ポリゴンめいっぱいの街並みが表示されたりする場面です。
(レインボーシックスベガス)
コマ落ちしているのが分かると思います。
処理落ちしたら、その時のフレームは描画をしないです。
処理速度で最も大きいのはだいたい描画です。
状況により、描画をせずにして時間経過における座標変化速度を維持しようとするのです。
PS3の3Dゲームとかが分かりやすいでしょうか。表示物が多いとすぐコマ落ちするんで。
マイクロソフトのXNAライブラリは描画ループで標準装備されていました。
次回は要望があればOpenSiv3Dでそれの実装コードの記事を載せたいと思います。数行追加すればできますね。
ついでにゲームでよくある一時停止についてもやるかも?
分かりにくい点などご指摘いただければ修正いたします。