ゲームフレームワーク的なものを作る。(3)〜Graphicsクラス〜

前回「ゲームフレームワーク的なものを作る。(2)〜Gameクラスに描画機能を追加〜 - while( c++ );」、Gameクラスへ描画機能を追加しました。

このまま画像などの描画機能も追加していくとGameクラスが肥大化するので、以下のように描画機能だけGraphicsクラス的なものに分離してみましょう。

Graphics.h
class Graphics
{
    //  -------------------------------------------------------------------------------
    //  生成と破棄
    //  -------------------------------------------------------------------------------
public:
    /**
     *  コンストラクタ
     */
    Graphics( const WindowWeakPtr& window );
    /**
     *  デストラクタ
     */
    ~Graphics();

    //  -------------------------------------------------------------------------------
    //  基本機能
    //  -------------------------------------------------------------------------------
private:
    /**
     *  Direct3Dオブジェクトの生成
     */
    IDirect3D9* CreateDirect3D();
    /**
     *  Direct3Dデバイスオブジェクトの生成
     */
    IDirect3DDevice9* CreateDirect3DDevice();
    /**
     *  COMオブジェクト解放用関数オブジェクト
     */
    struct com_deleter
    {
        void operator()( IUnknown* p )
        {
            p->Release();
        }
    };

public:
    /**
     *  シーンのクリア
     */
    void Clear();
    /**
     *  シーンのレンダリング開始
     */
    bool BeginScene();
    /**
     *  シーンのレンダリング終了
     */
    void EndScene();
    /**
     *  画面の更新
     */
    void Update();

private:
    WindowWeakPtr window;                           ///<    Graphicsを関連付けたWindow
    std::shared_ptr< IDirect3D9 > direct3d;         ///<    Direct3Dオブジェクト
    std::shared_ptr< IDirect3DDevice9 > device;     ///<    描画担当
};
Graphics.cpp
/**
 *  コンストラクタ
 *
 *  @param  window  既存ウィンドウのweak_ptr
 */
Graphics::Graphics( const WindowWeakPtr& window )
    : window( window )
    , direct3d( CreateDirect3D(), com_deleter() )
    , device( CreateDirect3DDevice(), com_deleter() )
{
}

/**
 *  デストラクタ
 */
Graphics::~Graphics()
{
}


/**
 *  Direct3Dオブジェクトの生成
 */
IDirect3D9* Graphics::CreateDirect3D()
{
    IDirect3D9* p = Direct3DCreate9( D3D_SDK_VERSION );
    if( p == nullptr )
        throw std::runtime_error( "Direct3DCreate9" );
    return p;
}

/**
 *  Direct3Dデバイスオブジェクトの生成
 */
IDirect3DDevice9* Graphics::CreateDirect3DDevice()
{
    if( WindowPtr w = window.lock() )               //lockの失敗はありえないはず。。。
    {
        IDirect3DDevice9* p = nullptr;
        D3DPRESENT_PARAMETERS pp = { 0 };
        pp.Windowed = TRUE;                         //ウィンドウモードの場合はTRUEを指定
        pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
        HRESULT hr = direct3d->CreateDevice(
            D3DADAPTER_DEFAULT,
            D3DDEVTYPE_HAL,
            w->GetHandle(),                         //ウィンドウハンドルを渡す
            D3DCREATE_HARDWARE_VERTEXPROCESSING,
            &pp, &p
            );
        if( SUCCEEDED( hr ) )return p;
    }
    throw std::runtime_error( "CreateDevice" );
}


/**
 *  シーンのクリア
 */
void Graphics::Clear()
{
    const DWORD clear_flag = D3DCLEAR_TARGET;
    const D3DCOLOR clear_color = D3DCOLOR_XRGB( 0x22, 0x22, 0x22 );

    device->Clear( 0, nullptr, clear_flag, clear_color, 1.0f, 0 );
}

/**
 *  シーンのレンダリング開始
 */
bool Graphics::BeginScene()
{
    return SUCCEEDED( device->BeginScene() );
}

/**
 *  シーンのレンダリング終了
 */
void Graphics::EndScene()
{
    device->EndScene();
}

/**
 *  画面の更新
 */
void Graphics::Update()
{
    device->Present( nullptr, nullptr, nullptr, nullptr );
}
Game.h
class Game
{
    //  -------------------------------------------------------------------------------
    //  生成と破棄
    //  -------------------------------------------------------------------------------
public:
    /**
     *  コンストラクタ
     */
    Game( const WindowWeakPtr& window );
    /**
     *  デストラクタ
     */
    ~Game();

    //  -------------------------------------------------------------------------------
    //  基本機能
    //  -------------------------------------------------------------------------------
public:
    /**
     *  ゲーム1フレームの処理を行う
     */
    void Run();

private:
    Graphics graphics;              ///<    描画機能
};
Game.cpp
/**
 *  コンストラクタ
 *
 *  @param  window  既存ウィンドウのweak_ptr
 */
Game::Game( const WindowWeakPtr& window )
    : graphics( window )
{
    //その他のゲームの初期化処理
    ;

    std::cout << "ゲームの初期化成功" << std::endl;
}

/**
 *  デストラクタ
 */
Game::~Game()
{
    //その他のゲームの解放処理
    ;
}

/**
 *  ゲーム1フレームの処理を行う
 */
void Game::Run()
{
    //シーンの実行
    ;

    //バックバッファをクリアし、シーンのレンダリングを開始する
    //レンダリング終了後、画面を更新する
    graphics.Clear();
    if( graphics.BeginScene() )
    {
        //シーンの描画
        ;

        graphics.EndScene();
    }
    graphics.Update();
}
サンプル


今回はプログラムの動作を変えずにソースコードの内部構造を整理するいわゆるリファクタリングをしてみました。「リファクタリング」「クラス 肥大化」などで検索してみてください。

次回はID3DXFontを使った文字列の描画を行う予定です。