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

このQ&Aのポイント
  • ゲームのループ処理中にSleep(1)が1msでもどってこない問題が発生しています。
  • Sleep(1)が2ms程度かかることが原因で、固定された30FPSになりません。
  • より効率的なアイディアを求めています。
回答を見る
  • ベストアンサー

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くらいして戻ってきています。 なにかよいアイディアを持っている方がいらっしゃいましたら教えてください。 よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.2

え? Windowsの時間の有効精度って10ms単位じゃなかったっけ? いや、最近はそうでもないのかもしれないけど…… 高い精度の時間を使う場合はマルチメディアタイマを使います。 timeSetEventとか…… timeBeginPeriodとかtimeEndPeriodはマルチメディアタイマの機能だから、Sleepとは直接関係ないと思うんだけど、システム全体のタイマ分解能が変わった結果、Sleepの精度も向上するということかな。 でも、それは保証された動作じゃないから、timeSetEventとか使う方が正攻法だと思います。

ordinary_man
質問者

お礼

timeSetEventを使用してきれいに30fpsを作ることができました、 ありがとうございました。 proogramerさんもありがとうございました、 http://howdoyoudo.my-sv.net/ こちらのサイトも非常に役に立ちました。 ありがとうございました。

その他の回答 (2)

回答No.3

magicalpassさんのおっしゃる通り、 正確に時間をはかるのであれば、 timeSetEventで精度のよいコールバックを受け取れます、 また、Sleepとは異なりますが、 QueryPerformanceCounterでμsの計測も可能ですよ。 http://howdoyoudo.my-sv.net/index.php?select=program&option=fps ↑このサイトにサンプルコードが上がっているので参考にしてみてはどうでしょうか?

参考URL:
http://howdoyoudo.my-sv.net/
回答No.1

確かにSleepは精度が悪いので有名です。 timeBeginPeriod(1) timeEndPeriod(1) は使っていますでしょうか? 多少は精度が向上するかもしれません。

関連するQ&A

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

    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で待機状態になるということでよろしいのでしょうか?ご教授お願いします。

  • 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からのキューを出しているということでいいのでしょか?

  • 質問なのですが・・・

    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が通らないのですがどうしたら通るようになるのでしょうか。

  • 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で同等の関数は定義できるのでしょうか?。

  • ウィンドウ内でマウスが乗ると更新が止まります・・

    ウィンドウプロシージャ周りを触っているのですが、  ・ウィンドウにマウスが乗っていつつ、マウスが動いている時  ・キーボードーを押した瞬間 にメインループに処理が回らず 全体の処理が止まってしまいます。 上の問題を解決するには、どうすれば良いでしょうか? ※以下コード ---------------------------------------------- while(TRUE) { if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if(msg.message == WM_QUIT) { break; } else { TranslateMessage(&msg); DispatchMessage(&msg); } } else { // 処理メッセージが無いとき WINDOWPLACEMENT wndpl; GetWindowPlacement(hWnd, &wndpl); if((wndpl.showCmd != SW_HIDE) && (wndpl.showCmd != SW_MINIMIZE) && (wndpl.showCmd != SW_SHOWMINIMIZED) && (wndpl.showCmd != SW_SHOWMINNOACTIVE)) { ... ゲームのような、常時更新が必要なループ処理 ... } } Sleep(1); // 最小化等でフリーズしないため } ---------------------------------------------- //以下メッセージ処理側の一部 case WM_KEYDOWN: if (wParam == VK_ESCAPE) { PostQuitMessage(0); } break; case WM_MOUSEMOVE: return DefWindowProc(hWnd, msg, wParam, lParam); default: return DefWindowProc(hWnd, msg, wParam, lParam); ---------------------------------------------- また、ゲームなどのリアルタイム更新に向いた ウィンドウプロシージャの作り方などの説明サイト等ご存知でしたら そちらも教えて頂けると幸いです。

  • 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が送られることはありえないと思うのですが、なぜでしょうか。 何か重大な思い違いをしているのでしょうか・・?

  • 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();//プログラ ムのメイン部分 ↑    ↑ }        ↑                   ↑                **ここで使ってます** 関数の内部処理は何度も確認したので間違ってないと思います。 ずっとこのバグについて考えいろいろ試しましたが、 結局原因はわからずここに助けを求めに来ました。 お願いします。

  • メッセージループ

    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 { } このソースで実行して消したら終了しませんでした。 なぜ終了できなかったのでしょうか?

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

    メインループでメッセージを拾ってモードレスで表示した画面の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()の使い方が間違っているのでしょうか。

専門家に質問してみよう