第2章 Windowsプログラムをゲーム用に改造する

2-3 DirectDrawオブジェクトの初期化・開放処理を追加する

スケルトンプログラムにDirectDrawを組み込み、ウィンドウを640×480ピクセルのフルスクリーンに設定する。
プログラムの流れは次のようになる。

(a) 準備

1.DirectDrawラッパー関数の準備

Microsoftが無料公開しているDirectDrawのラッパー関数「ddutil.cpp」を利用すると、DirectDraw系の処理が簡単に作成できるので、これを利用する。
プロジェクトのフォルダにMicrtosoftのDirectDrawラッパー関数「ddutil.cpp」「ddutil.h」をコピーし、コピーしたファイルをプロジェクトに追加(「プロジェクト」→「プロジェクトへ追加」→「ファイル」)する

2.DirectDraw関係のヘッダ・ファイルをインクルード

DirectDrawを利用するには、「ddraw.h」をインクルードする必要がある。また、DirectDrawのラッパー関数「ddutil.cpp」を利用するには、「ddutil.h」をインクルードしなければならない。

#include <ddraw.h>
#include "ddutil.h"

(b) DirectDrawオブジェクトの生成と初期化を行う関数を作成する

  1. プロトタイプ宣言に、以下の行を追加する
    HRESULT InitializeDraw(HWND);
  2. グローバル変数にDirectDrawオブジェクトを宣言する
    LPDIRECTDRAW7 g_pDD = NULL; // DirectDraw オブジェクト
    LPDIRECTDRAWSURFACE7 g_pDDSPrimary = NULL; // プライマリ・サーフェイス
    LPDIRECTDRAWSURFACE7 g_pDDSBack = NULL; // バック・サーフェース
  3. DirectDrawオブジェクトの生成・初期化を行う関数をInitApp関数の下に作成する
    //-----------------------------------------------------------------------------
    // 関数名 : InitializeDraw() 
    // 機能概要: Direct Draw オブジェクトの生成
    // 戻り値 : 正常終了のとき:DD_OK、異常終了のとき:エラーコード
    //-----------------------------------------------------------------------------
    HRESULT InitializeDraw(HWND hWnd)
    {
        DDSURFACEDESC2      ddsd;
        DDSCAPS2            ddscaps;
        HRESULT             hRet;
    
        ///////////////////////////////////////////////////////////////////////////
        // DirectDraw メインオブジェクトの作成
        ///////////////////////////////////////////////////////////////////////////
        hRet = DirectDrawCreateEx(NULL, (VOID**)&g_pDD, IID_IDirectDraw7, NULL);
        if (hRet != DD_OK)
            return InitFail(hWnd, hRet, "DirectDrawCreateEx FAILED");
    
        // 協調レベルの設定
        hRet = g_pDD->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT);
        if (hRet != DD_OK)
            return InitFail(hWnd, hRet, "SetCooperativeLevel FAILED");
    
        // ビデオモードの設定 640x480x8
        hRet = g_pDD->SetDisplayMode(640, 480, 8, 0, 0);
        if (hRet != DD_OK)
            return InitFail(hWnd, hRet, "SetDisplayMode FAILED");
    
        // プライマリ・サーフェイスの生成
        ZeroMemory(&ddsd, sizeof(ddsd));
        ddsd.dwSize = sizeof(ddsd);
        ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
        ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
        ddsd.dwBackBufferCount = 1;
        hRet = g_pDD->CreateSurface(&ddsd, &g_pDDSPrimary, NULL);
        if (hRet != DD_OK)
            return InitFail(hWnd, hRet, "CreateSurface FAILED");
    
        // バック・サーフェイスの生成
        ZeroMemory(&ddscaps, sizeof(ddscaps));
        ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
        hRet = g_pDDSPrimary->GetAttachedSurface(&ddscaps, &g_pDDSBack);
        if (hRet != DD_OK)
            return InitFail(hWnd, hRet, "GetAttachedSurface FAILED");
    
        return DD_OK;
    
    }

DirectDrawの各オブジェクトの生成に失敗したときに実行するInitFail関数を作成していないため、ここでビルドしてもエラーになる。

(c) DirectDrawオブジェクトの生成に失敗したときに実行する関数を作成する

DirectDrawオブジェクトの生成に失敗したとき、以下の処理を行わせる関数を作成する。

  1. エラーメッセージをダイアログボックスで表示する
  2. DirectDrawオブジェクトを開放する関数ReleaseDrawを実行する
    (ReleaseDraw関数はまだ作成していない)

プログラム作成手順は次のとおり。

  1. プロトタイプ宣言に、以下の行を追加する
    HRESULT InitFail(HWND hWnd, HRESULT hRet, LPCTSTR szError,...);
  2. エラー処理を行う関数をInitializeDraw関数の下に作成する
    //-----------------------------------------------------------------------------
    // 関数名 : InitFail()
    // 機能概要: 初期化に失敗したときのメッセージ表示関数
    // 引数例 : InitFail(hWnd,hRet,"Err String");  			文字列の表示
    //			   InitFail(hWnd,hRet,"Err Code %d %d", code, err); 書式指定の表示
    // 戻り値 : hRetの値(エラーコード)
    //-----------------------------------------------------------------------------
    HRESULT InitFail(HWND hWnd, HRESULT hRet, LPCTSTR szError,...)
    {
        char        szBuff[128];
        va_list     vl;
    
        va_start(vl, szError);
        vsprintf(szBuff, szError, vl);
        ReleaseDraw();
        MessageBox(hWnd, szBuff, "ERROR", MB_OK);
        DestroyWindow(hWnd);
        va_end(vl);
    
        return hRet;
    
    }
  3. この関数では、vsprintf関数を使用しているが、この関数を利用するにはstdio.hをインクルードしなければならない。
    #include <stdio.h>

DirectDrawの各オブジェクトを開放するReleaseDraw関数を作成していないため、ここでビルドしてもエラーになる。

(d) DirectDrawオブジェクトを開放する関数を作成する

ウィンドウを閉じるとき(ゲームが終了するとき)に、生成済みのDirectDrawオブジェクトを開放する関数を作成する。
プログラム作成手順は次のとおり。

  1. プロトタイプ宣言に、以下の行を追加する
    void ReleaseDraw(void);
  2. 生成済みのDirectDrawオブジェクトを開放する関数をInitFail関数の下に作成する
    //-----------------------------------------------------------------------------
    // 関数名 : ReleaseDraw()
    // 機能概要: Direct Draw オブジェクトの削除
    //-----------------------------------------------------------------------------
    void ReleaseDraw(void)
    {
        if (g_pDD != NULL)
        {
            if (g_pDDSPrimary != NULL) // プライマリ・サーフェイス
            {
                g_pDDSPrimary->Release();
                g_pDDSPrimary = NULL;
            }
            g_pDD->Release(); // DirectDrawオブジェクト
            g_pDD = NULL;
        }
    
    }

ここまでで、DirectDrawオブジェクトの生成、開放を行う関数が作成できた。しかし、これらの関数を使う処理はまだ組み込んでいない。

(e) 各関数を実行する処理を追加する

関数を作っただけでは実行されないので、各関数を適切な場所で実行するようプロうグラムをさらに修正する。

  1. ウィンドウの生成後にInitializeDraw関数を実行するようWinMain関数を修正する。InitApp関数を実行している場所の下に、以下のプログラムを追加する。
    /* Direct Draw Object の初期化 */
    if (InitializeDraw(hWnd) != DD_OK) return FALSE;
  2. ウィンドウを終了するときにDirectDrawオブジェクトを開放するようWinProc関数を修正する。
    case WM_DESTROY: // 閉じるボタンをクリックした時
        ReleaseDraw();
        PostQuitMessage(0); // WM_QUITメッセージを発行
        break;

ここまでで、DirectDrawオブジェクトの生成、開放を行うようになった。

また、フルスクリーンでゲームをする場合、Windows標準のマウスカーソルを消す必要があるため、WinProc関数に以下のプログラムを追加する。

case WM_SETCURSOR: // カーソルの設定
    SetCursor(NULL);
    break;

(f) プログラムのビルド&実行

ついにビルド&実行するときが来ました。しかし、ビルドの前にDirectDraw関係のライブラリを使用できるよう、プロジェクトの設定を変更しなければならないので、次のように設定する。

  1. 「プロジェクト」→「設定」を選択
  2. 「リンク」タブをクリックし、「オブジェクト/ライブラリ モジュール」に以下のライブラリを追加
    • ddraw.lib
    • dxguid.lib
    • winmm.lib


  3. 追加したら「OK」ボタンをクリック

この状態でビルド、実行を行うと画面が消える。(真っ黒なウインドウが表示される)

※プライマリ・サーフェイスに何も画像を送ってなく、またフリップ処理を行っていないため、ウィンドウは何も変化しない
※ウィンドウを終了させるにはESCキーまたはF12キーを押す


[ TOP ] [ Next ]