• 締切済み

FPS制御について

今DirectDrawを使ったプログラムを組んでいて、そのプロジェクト内でFPSの制御関数(図1)を作りました。その関数は引数を1つ持っていて、その引数に渡した値がそのままフレームレートになるはずなのですが、実際は引数に指定した値よりもフレームレートが落ちています。   図1 FpsControl(60); ↑           1/60フレームレート FPS制御をしていない時にFPSを計ったときには500~600fps は出ていましたので処理自体が遅いわけではないと思います。 FPS制御関数はメッセージループ部分(図2)で使っています。   図2 while(TRUE){ //メッセージがある場合 if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)){ if(msg.message == WM_QUIT) break; TranslateMessage(&msg); DispatchMessage(&msg); }else{ //メッセージが無い場合 if(FpsControl(60))Game_Main();//プログラ ムのメイン部分 ↑    ↑ }        ↑                   ↑                **ここで使ってます** 関数の内部処理は何度も確認したので間違ってないと思います。 ずっとこのバグについて考えいろいろ試しましたが、 結局原因はわからずここに助けを求めに来ました。 お願いします。

  • to4
  • お礼率37% (16/43)

みんなの回答

  • cherry3
  • ベストアンサー率39% (18/46)
回答No.2

開発環境や実際のFpsControl関数が何をやってるかわかりませんが、 とりあえず下記のようにやればできると思います。 // メッセージループ while(TRUE){ if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) ){ // 通常のWindowメッセージの処理 : : } else{ // FPS制御 static INT now_time = 0, old_time = 0; timeBeginPeriod(1); now_time = timeGetTime(); timeEndPeriod(1); if( (now_time-old_time) >= (1000/60) ){ old_time = now_time; // メイン処理 Game_Main(); } } }

  • honiyon
  • ベストアンサー率37% (331/872)
回答No.1

こんにちは、honiyonです。  精密にフレームレートを計算するには、様々な処理にかかる時間を考慮しないとダメだと思います。 FpsControl(60) とすると、60fpsだから、0.1msec待機する、という処理になっていませんか?  例えば表示処理に0.05msecかかっていたとすれば、1フレームにつき0.05msecの誤差が出ます。これを考慮しないといけません。  これの解決の一例ですが、  1.処理の開始にFpsControl_Startを呼び出す。(ここで時間計測開始)  2.表示処理を行う  3.FpsControl_Wait(60)を呼び出す。    ここで60fps計算で、0.1msecまたならければならない。しかし1~3までくるのに0.05mesecかかった。    0.1msec - 0.05msec = 0.05msecの停止とする。ただし、計算結果がマイナス(処理速度がたりない)場合は停止せずにreturnする。  なんて形にすれば良いと思います。    ちょっと分かりづらい説明かも知れませんが伝わりましたでしょうか(^^;  参考になれば幸いです(.. #的外してたらスイマセン...

関連するQ&A

  • PeekMessageについて

    確認したいのですが、 MSG msg; while(TRUE) { if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if(msg.message==WM_QUIT) { return (int) msg.wParam; } TranslateMessage(&msg); DispatchMessage(&msg); } else { } } このPeekMessageというものですがキューに溜めているということでいいのでしょうか。 後、 MSG msg; while(TRUE) { if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if(!GetMessage(&msg,NULL,0,0)) { return (int) msg.wParam; } if(msg.message==WM_QUIT) { return (int) msg.wParam; } TranslateMessage(&msg); DispatchMessage(&msg); } else { } } の if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if(!GetMessage(&msg,NULL,0,0)) { return (int) msg.wParam; } はキューから出してGetMessageは待機してるということでいいのでしょか? if(PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)) { if(!GetMessage(&msg,NULL,0,0)) { return (int) msg.wParam; } これはキューの中は出さないで、GetMessageでPeekMessageからのキューを出しているということでいいのでしょか?

  • FPSについて

    一つ質問なのですが、FPSの計測したいのですが、以下のソースでやるとFPSが57になってしまうのですが。 どうしたらFPSを60にすることが出来るのでしょうか? 多分ここら辺だろうなというところを載せます。 void FPSCount(void){ static DWORD before_time = timeGetTime(); // 以前の時間 DWORD now_time = timeGetTime(); // 現在の時間 static DWORD fps_ctr = 0; TCHAR buff[80]; // 文字列表示用バッファ if(now_time - before_time >= 1000){ // 初期化 before_time = now_time; *fps = fps_ctr;     wsprintf(buff,_T("%d\n"),fps_ctr);     OutputDebugString(buff);     fps_ctr = 0; } fps_ctr++; } // エントリポイント int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )      ・      ・      ・ // メッセージループ while(true) { if (PeekMessage(&msg, NULL, 0,0,PM_REMOVE)) { if (msg.message == WM_QUIT) break; TranslateMessage(&msg); DispatchMessage(&msg); } else { // 同期処理 if (timeGetTime() - dwStart >= 1000.0/FPS) { FPSCount(); // 時間更新 dwStart = timeGetTime(); fps=0; // 描画処理 Draw(); } } Sleep(1); } timeEndPeriod(1); // 終了処理 Cleanup(); // 戻り値を返します。 return (int)msg.wParam; } } です。 環境はVC+2005です。

  • メッセージループについて

    while(true) { if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if(msg.message==WM_QUIT) break; DispatchMessage(&msg); if(!GetMessage(&msg,NULL,0,0)) { } } else { } これはpeekMessageがメッセージを取り出してメッセージがあったら if(msg.message==WM_QUIT) break; DispatchMessage(&msg); if(!GetMessage(&msg,NULL,0,0)) を実行して、GetMessage()で待機してもし、メッセージがWM_QUITならGetMessageにWM_QUITのメッセージを渡してメッセージが消えてPeekMessageはメッセージキューがないため、0を返し永遠にelseを繰り返すという認識でよろしいのですか? あと、while(true) { if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if(!GetMessage(&msg,NULL,0,0)) { } if(msg.message==WM_QUIT) break; DispatchMessage(&msg); } else { } if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))がWM_QUITのメッセージで そしてメッセージが消えてGetMessageで待機状態になるということでよろしいのでしょうか?ご教授お願いします。

  • LinuxでDoEvents()同等機能

    Linux初心者です。 2.6-18-at9 Debianで及ばずながらマルチスレッドのプログラムを書いています。 VBにはOSにコントロールを戻すDoEventsという機能があります。 Windows/VC++ではこれと同等機能の関数を使っています: DWORD DoEvents(VOID) { MSG msg; while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ){ if ( msg.message == WM_QUIT ){ return( msg.message ); } TranslateMessage( &msg ); DispatchMessage( &msg ); } return( 0 ); } どなたかの示唆によるもので内容はよく理解していませんが、Windows下ではこれで長年つかえてきました。 Linux-gccで同等の関数は定義できるのでしょうか?。

  • Sleep(1)が1msでもどってこない。

    Sleep(1)が1msでもどってこない。 ゲームのループ処理を作っていまして、 空いている時間をシステムに返すためにSleep(1)を呼んで いるのですが、 while( msg.message != WM_QUIT ) { if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } else { //ゲーム的な処理 //時間があまればSleep() } } といった定番なことをしているのですが、 30FPSで固定されません。 調べてみるとSleep(1)が2msくらいして戻ってきています。 なにかよいアイディアを持っている方がいらっしゃいましたら教えてください。 よろしくお願いします。

  • 質問なのですが・・・

    while(true) { if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if(msg.message==WM_QUIT) break; DispatchMessage(&msg); } else { if(FAILED(Render(g_pD3DDevice))) DestroyWindow(hWindow); } } でRenderが通らないのですがどうしたら通るようになるのでしょうか。

  • メッセージループ

    while(true) { if(PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)) { if(msg.message==WM_QUIT) break; DispatchMessage(&msg); if(!GetMessage(&msg,NULL,0,0)) { return (int)msg.wParam; } } } else { } このソースで実行して消したら終了しませんでした。 なぜ終了できなかったのでしょうか?

  • APIのメッセージループの流れとTranslateMessage

    while(GetMessage(&msg, NULL, 0, 0) > 0){ TranslateMessage(&msg); DispatchMessage(&msg); } もしも「a」が押されたときは、 GetMessageで受け取って TranslateMessageでWM_CHARに変換され DispatchMessageでWM_CHARとしてのメッセージが送られる という流れになるはずです。 けど、実際には一度プロシージャにWM_KEYDOWNが送られます。 TranslateMessageが先にメッセージを変換してるので、WM_KEYDOWNが送られることはありえないと思うのですが、なぜでしょうか。 何か重大な思い違いをしているのでしょうか・・?

  • モードレスダイアログのタブ移動

    メインループでメッセージを拾ってモードレスで表示した画面のTabキー制御を行いたいのですが、以下のプログラムでTabキーはコントロール間を移動しますが、移動の順番がタブオーダーと全く違います。 ------------------------------------------------- // メイン ウィンドウを作成して、実行します Form1^ m_form = gcnew Form1(); m_form->Show(); msg.message = WM_CREATE; while (msg.message != WM_QUIT) { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (!IsDialogMessage( (HWND)m_form->Handle.ToPointer(), &msg )) { // メッセージが未処理の場合は処理を行う TranslateMessage(&msg); DispatchMessage(&msg); } } } ------------------------------------------------- m_form->ShowDialog(); にしたり、上記ループを Application::Run(gcnew Form1()); に変更するとちゃんとタブオーダーの順番で移動します。 訳有りで、ループ処理を変えたくはありません。 ネットで調べる限りタブ移動について「IsDialogMessage」を 入れるという疑問はあったのですが、それ以降の動作については 何も書かれていないようです。 上記ループの書き方でタブ移動がうまく行えない場合が あるのでしょうか? どなたかご存知でしたら教えてください

  • PeekMessage()について

    Windowsフォームアプリケーションです。 ループさせたいイベント(button1)中に、button2のイベントを行いたいのでPeekMessage()を使って以下のようにしました。 private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { while(1){ PeekMessage(&msg, NULL, 0, 0, PM_REMOVE); TranslateMessage(&msg); DispatchMessage(&msg); // ループさせたいイベント ・・・・・・・・・・・・・・・・・・・・ } } private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) {    ・・・・・・・・・・・・・・・・・・・・ } アプリケーション起動後、button1をクリックし、後にbutton2をクリックしようとすると代わりにbutton1がクリックされてしまいます。 PeekMessage()の使い方が間違っているのでしょうか。