ページ 11

ゲームループについて質問です

Posted: 2012年11月01日(木) 14:07
by 奥兵
現在Windowsプログラミングでゲームループを作ろうとしています。
多分メッセージ処理の関係だと思うのですが、ウィンドウを移動したりキーを押した時しか描画が呼ばれません。

コード:

void DemoApp::RunMessageLoop()
{
    MSG msg;

    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}
そこで、以下のコードに書き換えてみたのですが、こちらも最初は描画が呼ばれておらず
キー入力をするとその間だけ描画が呼ばれ、ウィンドウを移動させるとその後も描画が呼ばれ続けます。
目標はゲームループの作成ですアドバイスお願いします。ちなみに小生のプログラミング能力は素人に毛が生えた程度です。

コード:

void DemoApp::RunMessageLoop()
{	
	MSG msg;

		for(;;){
			if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
				if (GetMessage(&msg, NULL, 0, 0) > 0) {
					TranslateMessage(&msg);
					DispatchMessage(&msg);
				}
				else
					break;
			}
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		} 
}
以下プロシージャです

コード:

LRESULT CALLBACK DemoApp::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    LRESULT result = 0;

	static System *system;

    if (message == WM_CREATE)
    {
        LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
        DemoApp *pDemoApp = (DemoApp *)pcs->lpCreateParams;

        ::SetWindowLongPtrW(
            hwnd,
            GWLP_USERDATA,
            PtrToUlong(pDemoApp)
            );

        result = 1;

		system = new System();
		//MessageBox(NULL,L"ループ確認",L"test",MB_OK);
		//OutputDebugStringA("WPro create\n");

    }
    else
    {
		//OutputDebugStringA("WPro create else\n");
		//system->FPSlock();
		system->FPScheck();
		
		
        DemoApp *pDemoApp = reinterpret_cast<DemoApp *>(static_cast<LONG_PTR>(
            ::GetWindowLongPtrW(
                hwnd,
                GWLP_USERDATA
                )));

        bool wasHandled = false;

        if (pDemoApp)
        {
            switch (message)
            {
            case WM_SIZE:
                {
                    UINT width = LOWORD(lParam);
                    UINT height = HIWORD(lParam);
                    pDemoApp->OnResize(width, height);
                }
                result = 0;
                wasHandled = true;
                break;

            case WM_PAINT:
            case WM_DISPLAYCHANGE:
                {
                    PAINTSTRUCT ps;
                    BeginPaint(hwnd, &ps);
                    pDemoApp->OnRender();
                    EndPaint(hwnd, &ps);
                }
                result = 0;
                wasHandled = true;
                break;

            case WM_DESTROY:
                {
                    PostQuitMessage(0);
                }
                result = 1;
                wasHandled = true;
                break;
			default:
				{
                    PAINTSTRUCT ps;
                    BeginPaint(hwnd, &ps);
                    pDemoApp->OnRender();
                    EndPaint(hwnd, &ps);
                }
			break;
            }
        }

        if (!wasHandled)
        {
            result = DefWindowProc(hwnd, message, wParam, lParam);
        }
    }

    return result;
}

Re: ゲームループについて質問です

Posted: 2012年11月01日(木) 20:30
by softya(ソフト屋)
これだけの情報だと答えられない人が多いかと。
しかし、どうやって描画メッセージWM_PAINTを定期的に発生させているのでしょうか?

Re: ゲームループについて質問です

Posted: 2012年11月01日(木) 21:31
by 奥兵
ソフト屋さん、お返事ありがとうございます。

メッセージ処理の部分のPAINTを毎度呼ぶ方法はぱっと出て来なかったので、メッセージ処理のswitch文のdefaultに描画と同じ処理を持たせました。
pDemoApp->OnRender();が描画の本体部分を呼んでいます。
OnRenderは簡単な図案と一定スピードで回転する文字列を描画するだけの内容で、Direct2Dのサンプルにわずかに手を入れただけです。
文字列の回転はOnRenderが呼ばれる度にOnRender内部で角度の値を一度づつ増加させています。
現在走らせてみると、90度から始まった回転が10度かそこら動いたら止まってしまいます。
そこからキーを押したりウィンドウの移動をすると回転を初め、キーの場合は押している間、ウィンドウの移動の場合は以降回転が続きます。
なんとなくですが、プログラムの挙動からメッセージ処理関連が怪しいとは思ったのですが、他にどの部分を晒せばいいのかわからないのでプロジェクトを貼ります。
といってもDirect2Dのサンプルに少々付け足しただけです。Vista以降のOSでDirectXが入ってないと動かないかも知れません。

http://www4.gigafile.nu/v3/?23fcecb242b ... 5164bc450f

Re: ゲームループについて質問です

Posted: 2012年11月01日(木) 21:41
by softya(ソフト屋)
defaultでやるのは間違いです。
自分でタイマーで強制的に使うか何かしないとWM_PAINTはウィンドウ操作時にしか発生しませんね。

ところで、DirectXのサンプルがSDKに付属しているはずでが参考に見られていないのでしょうか?
DirectX sample viewerから参照できるはずですが。
それか、ちゃんとしたDirectXの入門書を買われるべきです。

Re: ゲームループについて質問です

Posted: 2012年11月01日(木) 22:09
by へにっくす
WM_PAINTメッセージは領域を消去された時しか呼ばれません。
消去される場合とは?ウィンドウが裏に隠れて、また表にでたときとかです。
なのでウィンドウがその位置に表示されたままですと、何も起きないのです。
つまり自分で領域を消去する関数を呼ばないといけないのです。
InvalidateRect関数がそれです。(すぐ反映させたい場合はUpdateWindow関数も必要)
領域の消去と有効化
描画の一括処理
この関数を定期的に呼べばよいかと。
また定期的にイベントを発生させるにはSetTimer、KillTimer、WM_TIMERメッセージですね。
タイマー

つまり、RunMessageLoopメソッドはいじる必要がないのです。
口を酸っぱくして言ってるのに、また変えてるんですねえ…

Re: ゲームループについて質問です

Posted: 2012年11月01日(木) 22:20
by softya(ソフト屋)
無理して分からないDirectXを使う必要はないと思うんですよ、
DXライブラリで十分色んな事が出来ますから。
DirectXじゃないと行けない理由は何でしょうか?

【補足】
兎に角、DirectXで作るなら基本的なWindowsの仕組みを理解しないことには話になりません。
猫でもわかるWindowsプログラミングとかAPIで学ぶWindows徹底理解とか読まれ待てますか?

【さらに補足】
へにっくす さんが書きました: つまり、RunMessageLoopメソッドはいじる必要がないのです。
口を酸っぱくして言ってるのに、また変えてるんですねえ…
マイクロソフト推奨の方法がメッセージループでレンダリングですね。
http://msdn.microsoft.com/ja-jp/library ... 85%29.aspx

Re: ゲームループについて質問です

Posted: 2012年11月01日(木) 23:34
by 奥兵
お返事ありがとうございます。

-へにっくすさん-
 そんな関数があったのですね、知りませんでしたありがとうございます。
ネットで調べつついろいろと試行錯誤してみたのですが、自力ではどうにも・・・
メッセージループは一応サンプルのままにしてあります。
下の方はWindowsプログラミングのゲームループについてググった時にこれと同種のものがワラワラ出てきたので
とりあえず突っ込んで回してみたのですが、どこがまずいのか理解できずそのまま質問してみることにしました。
やはりネットで調べた情報ではいけませんね。失礼しました(汗
とりあえず本屋でこの手の物の参考になりそうな本でも漁って見ることにします。

-ソフト屋さん-
  友人に勉強の為に一緒にDirect3Dをやろう、と勧められたのですが。
普通科高校の数学すら受けていない私には行列の時点で軽くお手上げになってしまって、とりあえずディメンションをひとつ落としてDirect2Dに手を付けてみたのですが・・・まぁ、ご覧の有様ですw
オリジナルのゲームを作成するのも好きで、プログラミング自体も下手の横好きなので両方同時に掘り下げようとしたのが間違いだったのだと思います。
しっかり分けて考えて、とりあえずプログラミングのほうはもう少し身の丈にあったところからやろうと思います。

Re: ゲームループについて質問です

Posted: 2012年11月01日(木) 23:57
by ISLe
Direct3DとWM_PAINTは連動しないからメッセージループでレンダリングするわけです。
WM_PAINTで描画するなら(&プログラムを大幅に変更したくないなら)へにっくすさんのおっしゃるとおりにするのが良いかと思います。


PeekMessageを使うにしてもきちんと使えば動作は変わらないんですよ。
TranslateMessageとDispatchMessageが2回ずつ呼ばれるようになってしまっているので同じウィンドウメッセージが2回ずつ届いているはずです。
参考にしたコードはこんなふうにはなっていないと思いますが。


Direct2DはDirect3Dのひとつ下ではありません。
Direct3Dの技術を応用した最新技術で、日本語資料も少なく、採用しているアプリケーションもあまり見ないですね。
2Dゲームには過ぎたコンポーネントです。
本来の意味での役不足です。

Re: ゲームループについて質問です

Posted: 2012年11月02日(金) 07:26
by AKIЯA
いきなりDirectXからやるのはハードルが高いですね。

順番に基礎から覚えて行った方がいいと思いますよ。
まずはWin32を覚えてWindowsのメッセージのやり取りの仕組みを覚えてからDXライブラリ使うと楽にできますよ。
いきなりDXライブラリでもいいと思いますが・・・

DirectXは難しそうで私は手を出していませんが(面倒だから手を出してないのですw)
DXライブラリの吸収力がすごすぎて(DirectXを手抜きで使えるから)
DirectX使わないとできなかったことがDXライブラリで簡単に出来るので
ここから一歩踏み出してDirectX勉強しようとしてませんが^^;