トップページ > 記事閲覧
FPSを正確に制御する方法
名前:MKII 日時: 2019/10/24 16:46

> 新・C言語 〜ゲームプログラミングの館〜 [DXライブラリ] > 3.14章 特定のFPSで動作させる方法 > dixq.net/g/03_14.html 最近 C# で DX ライブラリの使い方勉強中。以上の文章を読んで、試しにFPS制御を実装しました: ---------------------------------------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using DxLibDLL; namespace DXLib_TEST { class Program { // Global Timer public static System.Diagnostics.Stopwatch StopWatch = new System.Diagnostics.Stopwatch(); // Constants public const int FPS = 60; // Target FPS // Variables public static uint FrameCounter; public static double TimeOfFirstFrame; static void Main(string[] args) { // Use Main Window as Log Console Console.Title = "Log Window"; Console.WriteLine("Program started."); // Init DXLib DX.SetMainWindowText("DXLib TEST"); DX.ChangeWindowMode(DX.TRUE); DX.SetGraphMode(480, 320, 32); DX.SetAlwaysRunFlag(DX.TRUE); DX.SetWaitVSyncFlag(DX.FALSE); if (DX.DxLib_Init() == -1) { Console.WriteLine("DXLibrary failed to load. \nPress any key to exit."); Console.ReadLine(); return; } // Need to set after Init DX.SetDrawScreen(DX.DX_SCREEN_BACK); Console.WriteLine("DXLibrary loaded."); // Some Values double fps_counter = 0; // Average FPS in [target FPS] frames double time_record = 0; // record once per[target FPS] uint loops_waited_per_FPS = 0; // Main Loop StopWatch.Start(); while (DX.ProcessMessage() == 0 && DX.ClearDrawScreen() == 0) { FrameCounter++; // FPS Counter if (FrameCounter == 1) { TimeOfFirstFrame = StopWatch.Elapsed.TotalMilliseconds; } else if (FrameCounter < FPS) { fps_counter = 1000 / ((StopWatch.Elapsed.TotalMilliseconds - TimeOfFirstFrame) / FrameCounter); DX.SetMainWindowText($"[{fps_counter:0.00} FPS]"); } else if (FrameCounter % FPS == 0) { fps_counter = 1000 / ((StopWatch.Elapsed.TotalMilliseconds - time_record) / FPS); time_record = StopWatch.Elapsed.TotalMilliseconds; DX.SetMainWindowText($"[{fps_counter:0.00} FPS ({loops_waited_per_FPS} loops waited)]"); loops_waited_per_FPS = 0; } // Calculation // Task.Delay(64).Wait(); // Simulate low speed // Draw DX.DrawString(10, 10, $"Frame : {FrameCounter}", DX.GetColor(255, 255, 255)); DX.DrawString(10, 30, $"Timer : {StopWatch.Elapsed.TotalMilliseconds} ms", DX.GetColor(255, 255, 255)); DX.DrawString(10, 50, $"Ticks : {StopWatch.ElapsedTicks}", DX.GetColor(255, 255, 255)); // Wait before ScreenFlip to control fps while (CalculateWaitTime() > 0) { loops_waited_per_FPS++; DX.ProcessMessage(); } DX.ScreenFlip(); } // Exit DX.DxLib_End(); return; } private static double CalculateWaitTime() { return FrameCounter * 1000 / FPS - (StopWatch.Elapsed.TotalMilliseconds - TimeOfFirstFrame); } } } ---------------------------------------------------------------------------------------------------- ・DX.GetNowCount() の代わりに C# の Stopwatch 使った理由はオーバーフローを防ぐためです (自分のパソコン滅多に再起動しない、今の Uptime は既に 13 日以上…) ・精度を追求して Thread.Sleep() を使ってない(精度低いし、1ms 以下にもなれない) ---------------------------------------------------------------------------------------------------- 1FPSでも、120FPSでも期待通り動く、やったね! ですが、自分のパソコンで1秒(正確にいえば設定したフレーム)に...  ( ;゚Д゚)「50万回以上」もループする! 結果として、秒で50万回以上 DX.ProcessMessage() を執行しています。  (´・ω・`;) これ…大丈夫なの? ---------------------------------------------------------------------------------------------------- 編集:SetDrawScreen() を DxLib_Init() より前なら反映しないと発見しましたので、コードを修正しました。
メンテ

Page: 1 |

Re: FPSを正確に制御する方法 ( No.1 )
名前:管理人 日時:2019/10/25 00:27

> (´・ω・`;) これ…大丈夫なの? 何を以て大丈夫とするかによりますが、PCが壊れたりすることは無いです ただ、Sleep が無いと論理コアの一つを100%使い切るので、ノートPCなどではファンが回りだしたり、 夏場冷房が効いていない部屋で実行すると熱暴走する確率が少し上昇するかもしれません…
メンテ
Re: FPSを正確に制御する方法 ( No.2 )
名前:MKII 日時:2019/10/25 20:15

おっしゃる通りCPU使用率は常時25%(1コア)、いろいろ試した結果 SpinWait で対応しました。 秒50万回以上から秒2万回くらいになって、CPUの使用率無事下がってます。 質問の仕方が悪くてすみません。聞きたいのは:  DX.ProcessMessage() 秒になん万回を執行しても大丈夫ですか?
メンテ
Re: FPSを正確に制御する方法 ( No.3 )
名前:管理人 日時:2019/10/28 02:24

返信が遅くなり申し訳ありません >  DX.ProcessMessage() 秒になん万回を執行しても大丈夫ですか? はい、大丈夫です
メンテ
Re: FPSを正確に制御する方法 ( No.4 )
名前:MKII (解決) 日時:2019/10/28 19:33

お返事いただきありがとうございます。
メンテ

Page: 1 |

題名
名前
コメント
パスワード (記事メンテ時に使用)

   クッキー保存