本来は NURBS を解説するところですが、
このままでは何時終わるか分からないので、実際にプログラムを組む路線に変更します。
っていうか、俺が使わないから上手く解説できん。
2001年現在のゲームプログラムの主流は。DirectX であることは、疑いがないと思います。 DirectX は、8.0 になってから、初期化が簡単になり、プログラム作りが楽になりました。 と、いっても、初心者には、まだまだ作るのが大変です。 とりあえず、(同人で売れるくらいの?)ゲームを一本作る程度の仕事及び、 いろいろな Tips を目指して、作りたいと思います。
とりあえず、下のソースをダウンしてください。Visual C++ 6.0 のプロジェクトになっています。
かなり基本的なウィンドウズのプログラムです。ウィンドウしか表示しません
では、内容を見てみましょう。
Windows のプログラムは WinMain から始まります。
大まかな流れは、次のようになります。
ウィンドウの作成 ↓←─────────────────┐ メインループ │ ├──────┬────┐ │ ↓ ↓ ↓ │ 終了イベント 描画 キーなどのイベント │ │ └────┴──────┘ ↓ 確保したメモリの開放 ↓ 終了
まず、ウィンドウを作ります。
この処理はほとんど決まっているので、みんな一度作ったらそれをコピーして使っていると思います。
次にメインループがぐるぐる回っています。
ウィンドウズは(一度は聞いたことがあると思いますが)、イベント駆動型の取り扱いに適したOSです。
『キーが押された』、『マウスがクリックされた』等の処理が発生したときに、『イベント』が発生するので、
プログラマーは、それぞれのイベントに適した処理をします。
ウィンドウの左上の×ボタンを押した時は、終了のイベントが発生します。
終了イベントの発生を監視して、プログラムで使ったメモリなどの後片付けをした後に、
プログラムを終了します。
この後片付けを忘れると、メモリの空き領域が減っていき、
いき過ぎるとウィンドウズが正常に動作しないようになります。
では、一気にはじめの関数である WinMain を見てみましょう。
static bool s_end; // 終了フラグ int PASCAL WinMain(HINSTANCE hInst,HINSTANCE hPrev,char *CmdLine,int CmdShow) { s_end = 0; // ★★★★★ ウインドウの作成 RECT rect; SetRect(&rect, 0, 0, WIDTH, HEIGHT); DWORD style = (FULLSCREEN) ? WS_POPUP : WS_CAPTION|WS_SYSMENU|WS_BORDER|WS_MINIMIZEBOX; AdjustWindowRect(&rect, style, FALSE); // ウィンドウスタイルを設定したときの、ウィンドウの大きさを調べる int width = rect.right - rect.left; int height = rect.bottom - rect.top; WNDCLASS wc; ZeroMemory(&wc, sizeof(WNDCLASS)); wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); wc.hCursor = LoadCursor(NULL,IDC_ARROW); wc.hInstance = hInst; wc.lpfnWndProc = MsgProc; wc.lpszClassName = CAPTION; if(RegisterClass(&wc) == 0) return 0; //ウィンドウ作成に使用できる新しいウィンドウクラスを作成する。 HWND hWnd = CreateWindow(CAPTION // 登録されているクラス名 ,CAPTION // ウィンドウ名 ,style // ウィンドウスタイル ,CW_USEDEFAULT // ウィンドウの横方向の位置 ,CW_USEDEFAULT // ウィンドウの縦方向の位置 ,width // ウィンドウの幅 ,height // ウィンドウの高さ ,NULL // 親ウィンドウまたはオーナーウィンドウのハンドル ,NULL // メニューハンドルまたは子ウィンドウ ID ,hInst // アプリケーションインスタンスのハンドル ,NULL // ウィンドウ作成データ ); if(hWnd == NULL) return 0; ShowWindow(hWnd, SW_SHOW); UpdateWindow(hWnd); // ★★★★★ メインループ MSG msg; while (!s_end) { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){ // メッセージの処理 TranslateMessage(&msg); DispatchMessage(&msg); }else{ // メッセージが来ない時(後々、描画系の処理が入る) } } // ★★★★★ 終了 return 0; }
なお、WIDTH, HEIGHT, FULLSCREEN, CAPTION は main.h で定義しています。
これは、今後ゲームを作ることを考えると、解像度は変化しないと考え、このような方式にしました。
ない様ですが、AdjustWindowRect で、ウィンドウのサイズを計算し、RegisterClass で、背景色などの設定をし、
CreateWindow で、ウィンドウを作成します。
メインループでは、s_end が true になるのを待って、ループを回します。
PeekMessage がイベントを拾う関数で、メッセージがおきたら、TranslateMessage, DispatchMessage で
処理をします。
実際には、その中で wc.lpfnWndProc の MsgProc が呼ばれます。
まぁ、そんなもんだと思ってください。
MsgProc は、下の関数で、WM_CLOSE のイベント(もしくは WM_KEYDOWN のコマンド)で、
s_end を true にして、終了を促します。
つまり、このプログラムは、×ボタンを押すか、キーボードのどこかを押すと終了します。
LRESULT CALLBACK MsgProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) { switch (msg){ case WM_KEYDOWN: // 何かキーが押された case WM_CLOSE: // ×ボタンを押した s_end = true; return 1; break; default: break; } return DefWindowProc(hWnd,msg,wParam,lParam); }
あと、今回は特にメモリの確保をしていないので、後片付けですることはありませんでした。
このプログラムは、一般のウィンドウズプログラムで、Direct X はまだ出てきません。
次から、いよいよ Direct X のプログラムに入ろうと思います。