ホーム < ゲームつくろー! < オブジェクト指向設計編 < オブジェクト指向の根幹部分、オブジェクトの生成と初期化は誰がする?:サンプルプログラム


その9 オブジェクト指向の根幹部分、オブジェクトの生成と初期化は誰がする?:サンプルプログラム


 オブジェクト指向設計編その9「オブジェクト指向の根幹部分、オブジェクトの生成と初期化は誰がする」で説明した内容を踏まえたサンプルプログラムです。実行すると時間(時、分、秒)を表す簡単な時計が表示されます。


サンプルスクリーンショット


 今回は時計クラスのインスタンスを生成して外部ファイルからテクスチャを読み込む「ファクトリクラス」部分が本題です。プログラム中にテクスチャ名を指定するのではなく、外部ファイルに列挙して生成するようにしています。これにより、プログラムを変更しなくても時計の文字を変更する事が可能になります。


 以下のプログラムはClock.h、ClockTextureFileList.dat及びこのファイルに列挙されている10枚の数字テクスチャ(Tex0.jpg〜Tex9.jpg)をパスの通ったフォルダに置いて、プログラムを空のプロジェクトにコピペすることで完全に動きます。必要なファイル(main.cppを含む)はこちらからダウンロードできます(OODSmpNo9.lzh : 44.1kb)。上からデバッグしていくと、何をしているか良くわかるように1つのソースで完結させています。今回のポイントになりそうなところは太文字で示されています。尚、Unicodeモードでは動きません!マルチ文字モードに変更してください。
(もしうまく動かないようでしたら掲示板にてご連絡下さい)

メイン関数(main.cpp)
/// 外部ファイル参照テスト

#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")

#include <windows.h>
#include <tchar.h>
#include <d3d9.h>
#include <d3dx9.h>
#include "Clock.h"   // 時計クラスヘッダー


TCHAR gName[100] = _T("外部ファイル参照テスト");



LRESULT CALLBACK WndProc(HWND hWnd, UINT mes, WPARAM wParam, LPARAM lParam){
   if(mes == WM_DESTROY) {PostQuitMessage(0); return 0;}
   return DefWindowProc(hWnd, mes, wParam, lParam);
}

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
        // アプリケーションの初期化
        MSG msg; HWND hWnd;
        WNDCLASSEX wcex ={sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hInstance, NULL, NULL,
                                                                        (HBRUSH)(COLOR_WINDOW+1), NULL, (TCHAR*)gName, NULL};
        if(!RegisterClassEx(&wcex))
                return 0;

        if(!(hWnd = CreateWindow(gName, gName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
                                                                        NULL, NULL, hInstance, NULL)))
                return 0;

        // Direct3Dの初期化
        LPDIRECT3D9 g_pD3D;
        LPDIRECT3DDEVICE9 g_pD3DDev;
        if( !(g_pD3D = Direct3DCreate9( D3D_SDK_VERSION )) ) return 0;

        D3DPRESENT_PARAMETERS d3dpp = {0,0,D3DFMT_UNKNOWN,0,D3DMULTISAMPLE_NONE,0,
                                                                                                          D3DSWAPEFFECT_DISCARD,NULL,TRUE,0,D3DFMT_UNKNOWN,0,0}; 

        if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDev ) ) )
        if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDev ) ) )
        {
                g_pD3D->Release();
                return 0;
        }

        // 時計生成
        CClockFactory ClockFactory;
        IClock *pClock;
        if( !ClockFactory.CreateClock( g_pD3DDev, &pClock ) ){
                g_pD3DDev->Release();
                g_pD3D->Release();
                return 0;
        }

        ShowWindow(hWnd, nCmdShow);

        // メッセージ ループ
        do{
                Sleep(1);
                if( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ){ DispatchMessage(&msg);}
                // Direct3Dの処理
                g_pD3DDev->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );
                g_pD3DDev->BeginScene();

                // 描画
                pClock->Draw();

                g_pD3DDev->EndScene();
                g_pD3DDev->Present( NULL, NULL, NULL, NULL );
        }while(msg.message != WM_QUIT);

        g_pD3DDev->Release();
        g_pD3D->Release();

        return 0;
}

時計クラス・時計ファクトリ(Clock.h)
//// 時計クラス(簡易版)

#include <string>
#include <fstream>
#include <vector>
#include <time.h>

using namespace std;



// 時計インターフェイス
class IClock
{
public:
   // 数字テクスチャを登録
   virtual bool SetNumberTexture( DWORD Number, IDirect3DTexture9 *pTex ) = 0;
   // 描画
   virtual void Draw() = 0;
};


// 時計クラス
class CClock : public IClock
{
protected:
        vector< IDirect3DTexture9* > m_VctTex;  // テクスチャ配列
        IDirect3DDevice9 *m_pDev;               // 描画デバイス
        ID3DXSprite *m_Sprite;                  // スプライト
        BYTE m_Time[6];                         // 時分秒([0][1]:時、[2][3]:分、[4][5]:秒)
        FLOAT m_Angle;                          // 回転角度

public:
        // コンストラクタ
        CClock()
        {
                m_Sprite = NULL;
                m_VctTex.resize(10, NULL);
                m_Angle = 0;
        }

        // デストラクタ
        virtual ~CClock()
        {
                DWORD i;
                for(i=0; i<m_VctTex.size(); i++){
                        if( m_VctTex[i] != NULL) m_VctTex[i]->Release();
                }
                if(m_Sprite)
                        m_Sprite->Release();
        }

   // 数字テクスチャを登録
        virtual bool SetNumberTexture( DWORD Number, IDirect3DTexture9 *pTex ){
                if(Number>10) return false;     // 10以上は登録できない
                m_VctTex[Number] = pTex;
                return true;
        };

        // デバイス登録
        void SetDevice( IDirect3DDevice9 *pDev )
        {
                m_pDev = pDev;
                D3DXCreateSprite( pDev, &m_Sprite );    // スプライト生成
        }

        // 時刻を取得
        void Gettime()
        {
                time_t curtime;
                time( &curtime );
                tm *t = localtime(&curtime);
                m_Time[0] = t->tm_hour / 10;    m_Time[1] = t->tm_hour % 10;  // 時間
                m_Time[2] = t->tm_min / 10;     m_Time[3] = t->tm_min % 10;   // 分
                m_Time[4] = t->tm_sec / 10;     m_Time[5] = t->tm_sec % 10;   // 秒
        }

        // 描画
        void Draw()
        {
                if(!m_pDev)
                        return;   // デバイスが必要
                m_Angle+=0.03f;
                Gettime();
                DWORD i;
                D3DXMATRIX Mat, Rot, Scale;
                D3DXMatrixIdentity(&Mat);
                D3DXMatrixRotationZ( &Rot, D3DXToRadian(7.5+15*cos(m_Angle)) );
                D3DXMatrixScaling( &Scale, 2+sin(m_Angle), 2+sin(m_Angle), 1);
                Mat *= Scale * Rot;
                m_Sprite->Begin(0);
                for(i=0;i<6;i++){
                        Mat._41 = 100+i*(2+sin(m_Angle/3))*34 + (i/2)*5;
                        Mat._42 = 50;
                        m_Sprite->SetTransform( &Mat );
                        m_Sprite->Draw( m_VctTex[m_Time[i]], NULL, NULL, NULL, 0xffffffff );
                }
                m_Sprite->End();
        }
};






#define CLOCKTEXTURLIST _T("ClockTextureFileList.dat")   // テクスチャリストファイル名

// 時計生成ファクトリ
class CClockFactory
{
public:
   // 時計を生成
   bool CreateClock( IDirect3DDevice9 *pDevice, IClock **ppClock )
   {
      // 時計オブジェクト生成
      CClock *pClock = new CClock;

      // ファイル内からテクスチャ名リストファイルを取得
      vector<string> TexList;
      GetTextureNames( CLOCKTEXTURLIST, TexList );   // CLOCLTEXTURELISTは数字テクスチャ名が列挙されたファイル名

      // 取得したファイル名を頼りにテクスチャを作成
      DWORD i;
      for(i=0; i<TexList.size(); i++){
         IDirect3DTexture9* pTex = NULL;
         D3DXCreateTextureFromFile( pDevice, TexList[i].c_str(), &pTex );
         pClock->SetNumberTexture( i, pTex );   // テクスチャ登録
      }

      // デバイスをセット
      pClock->SetDevice( pDevice );

      *ppClock = pClock;
      return true;
   }

   // ファイルからテクスチャ名前を取得
   void GetTextureNames( _TCHAR* filename, vector<string> &List )
   {
           // ファイルオープン
           ifstream ifs;
           ifs.open( filename );
          if( !ifs.is_open() )  return;
           char name[256];
           while(!ifs.eof()){
                   ifs.getline( name, 256 );
                   List.push_back( name );      // テクスチャファイル登録
           }
   }
};