質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

507閲覧

全体の処理が止まるとフレームレートが乱れる現象に対応したい

RyuL

総合スコア24

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2022/10/02 03:35

現在のゲーム制作のフレームレートの処理において、ファイルの読み込み等で全体の処理が止まった際に、処理がまた動き始めた時にフレームレートが乱れ、少しの間ゲームが高速に動いてしまい、この問題を解消したいと思っています。

たぶんですが、毎フレームで現在の時間を取得し1フレームのウェイト時間を調整しているので、処理が止まっている間と現実の時間の差が出来てしまいフレームレートが乱れてしまっているのだと思っていますが、ではどうやって解消したらいいかを幾ら考えても思いつかないです。

色々とネット上で調べても、私が見た限りだと皆同じ様なコードをサンプルとして挙げていたので、良い情報が得られず困っていました。

現在のソースコード

C++

1void MainProc::FPS( void ) 2{ 3 static int fps_count = 0, count_0time = 0; 4 static int frame[60*60]; //60FTP * 60秒 5 int wait_time = 0, now_time = 0; 6 static int t = 0; 7 8 m_time_count++; 9 if( m_time_count >= ONE_MINUTE ) 10 m_time_count = 0; 11 12 fps_count = m_time_count % m_set_fps; 13 14 if( fps_count == 0 ) 15 { 16 // 60フレームの1回目 17 if ( t == 0 ) // 完全に最初なら待たない 18 wait_time = 0; 19 else // 前回記録した時間を元に計算 20 wait_time = count_0time + 1000 - GetNowCount(); // GetNowCount() 現在の時間をミリ秒で取得 21 } 22 else // 待つべき時間 = 現在あるべき時刻 - 現在の時刻 23 wait_time = (int)( count_0time + fps_count * ( 1000.0 / m_set_fps ) ) - GetNowCount(); 24 25 if( wait_time > 0 ) // 待つべき時間だけ待つ 26 Sleep( wait_time ); 27 28 now_time = GetNowCount(); 29 30 if( fps_count == 0 ) // 60フレームに1度基準を作る 31 count_0time = now_time; 32 frame[fps_count] = now_time - t; // 1周した時間を記録 33 t = now_time; 34 35 return; 36}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

検証してみたところ、fanaさんに図解でご指摘通りの原因でした。
ソースだと、フレーム数のカウンターである m_time_count と現在の時間から計算されるフレーム数にずれが生じて、そのずれている間は各フレームの待ち時間がゼロになっていました。
ただ、m_time_count はFTP(60とか30とか)の値になるとゼロにリセットされるので、処理が再開したタイミングで取得した現在の時間によって、どのくらいずれるかは毎回ランダムで、最小で0フレームのずれ(=ずれ無し)、最大でFTP-1(59とか29とか)のずれになっていた様です。

そこで単に m_time_count をゼロにリセットするメソッドを作って、読み込みに時間が掛かる処理が終わった直後にこのメソッドを実行することで問題は解決しました。

投稿2022/10/03 04:29

RyuL

総合スコア24

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

こういう話だろう,という絵を描いてみました.

時刻1から開始した処理が時刻4.5くらいまでかかってしまった場合の絵です.この場合,以降のウェイト判定の際に既に過ぎ去ってしまった時刻{2,3,4}に関して「必要ウェイト=0」と判定されるので,3回分ほど高速で動いてしまう,という話でしょう.
(また,そうこうしているうちに時刻5に達してしまうならば,次もウェイト=0になる)

イメージ説明

ここで,この現象の原因を,「時刻{2,3,4,...} がある時刻0を基準としてあらかじめスケジューリングされていることにある」のだと考えるならば,
長い処理を行う以前に決めたスケジュールは破棄してしまえばよいでしょう.
すなわち,下図のように,長い処理を実施する場合には,再スケジューリングを実施すればどうでしょう.
(当然,「どの処理が長いのか?」は既知なのだとして.)

イメージ説明

投稿2022/10/03 01:35

fana

総合スコア11658

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2022/10/03 01:47

もちろん「長い処理」が本当に長い(秒単位でかかるとか)場合には,別の既存回答のように別スレッドにしないとAPP自体が固まるのでよろしくないわけだが,せいぜい0.5秒みたいな場合であればこんな感じでごまかしちゃっても良いんじゃないかな?的な.
fana

2022/10/03 01:51

この回答の話みたいな「再スケジューリング」みたいなのをやるのであれば,このスケジューリングをしている部分だけを1個のクラスにしちゃえば楽なんじゃないかな. そしたら,「再スケジューリング」は単にオブジェクトを作り直せばOKだろう,っていう.
RyuL

2022/10/03 04:31

図解でご指摘した通りの原因が問題で、単にフレーム数をカウントしている変数をゼロにリセットするメソッドを作って、読み込み処理が終わった直後にこのメソッドを実行する事で問題は解決しました。 ご教授有難う御座いました。
guest

0

WinodwsやLinuxなどの立派なOSを積んでいるのであれば「マルチスレッド」で解決するのが定番ではないでしょうか。
時間の掛かる処理を別スレッドに追い出します。

投稿2022/10/02 04:05

thkana

総合スコア7639

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問