BMP 画像でスコアを表示

My.lib に登録されている SPRITE Class を継承して、画像を使ってスコアを表示します。
Library に登録されている Object Class を継承するサンプルとして参照して下さい。

前田稔(Maeda Minoru)の超初心者のプログラム入門

Object Class の説明

  1. 0~9の画像を表示するのに My.lib に登録されている SPRITE Object Class を継承した Anime Object Class を使います。
    SPRITE Object Class は一枚の大きな画像を格子状に区切り、それぞれを独立した画像(Sprite)として表示する汎用の Object Class で、 今回は「0~9」の数字を横に並べた画像を切り出してカウンタを表示します。
    SPRITE Class では、自動的に黒を透明色として表示してくれるので、数字画像の背景色には黒を使っています。
    今回のプログラムでは、わざわざ Anime Class に継承しなくても SPRITE Class をそのまま使う方が普通なのですが、 Library に登録されている Object Class を継承する場合のサンプルとして参照して下さい。
  2. 空の新規プロジェクトを作成して、次のファイルをフォルダーに格納して下さい。
    ファイル名ファイルの説明
    Main.cpp Main Program ファイル
    Anime.h Anime Object Class のヘッダファイル
    Anime.cpp Anime Object Class のプログラムファイル
    my.h 私有 Object Class Library のヘッダファイル
    my.lib 私有 Object Class Library のライブラリファイル
    imgnum.bmp 0~9の数字が横に並んだ画像ファイル
  3. SPRITE Class を継承した Anime Class のヘッダファイル Anime.h です。
    My.lib に登録されている SPRITE Class を継承するので、My.h を include します。
    全ての処理は SPRITE Object Class で行うので形式的に記述されているだけです。
    : public SPRITE で SPRITE Class を継承することを宣言します。
        /*★ CARD Object Header File  2006-12-01  前田 稔 ★*/
        //   BSprite Object Class を継承する
        #include "My.h"
    
        class Anime : public SPRITE
        { protected:
    
          public:
            Anime(HWND hWnd);               //Constructor
            ~Anime();                       //Destructor
    
        };
        
  4. SPRITE Class を継承した Anime Class のプログラムファイル Anime.cpp です。
    こちらも形式だけで、中身は何もありません。
    : SPRITE(hwnd) で継承した SPRITE Class の Constructor を呼び出します。
        /*★ Anime Object Class  2006-12-01  前田 稔 ★*/
        #include    
        #include    "Anime.h"
    
        // Anime Object Class 関数
        // コンストラクタ(オブジェクトの初期化)
        Anime::Anime(HWND hwnd) : SPRITE(hwnd)
        {
        }
    
        // デストラクタ(オブジェクトの終了)
        Anime::~Anime()
        {
        }
        

Main Program の説明

  1. My.lib に登録されている SHOOT Object Class を継承するので my.lib をリンクして下さい。
    クラスタブを選択して[プロジェクト][プロパティ][リンカ][入力]で追加する依存関係を編集して [my.lib] を追加します。
    リンカ/入力からリンクする代わりに #pragma でリンクすることも出来ます。
    #pragma comment(lib,"my.lib")
    ID_TIMER はタイマのIDです。
    *App は Anime Object Class の定義です。
    File[] はカウンタを表示する BMP 画像が格納されたファイルの名前です。
    g_CNT には表示するカウンタの値を格納します。
        /**************************************************/
        /*★ SPRITE を継承してカウンタを表示    前田 稔 ★*/
        /**************************************************/
        #define     NAME    "Counter"
        #include    <windows.h>
        #include    "Anime.h"
        #pragma     once
        #pragma     comment(lib,"my.lib")
    
        #define     SAFE_DELETE(p)  { if (p) { delete (p);     (p)=NULL; } }
        #define     ID_TIMER    (WM_APP + 0)
    
        Anime       *App= NULL;
        char        File[MAX_PATH]= "imgnum.bmp";
        int         g_CNT= 0;
        
  2. WM_CREATE: で Anime Class をインスタンス化して、スコアを表示する数字の画像を入力します。
    10,1 は Sprite の区切り方で、imgnum.bmp には「0~9」の数字が横一列に並んでいます。
    キーのスキャンとスコアを表示するタイミングをタイマで設定します。
            case WM_CREATE:
                App= new Anime(hWnd);
                if (App->Load(File,10,1)==FALSE)
                {   PostMessage(hWnd,WM_CLOSE,0,0);
                    break;
                }
                SetTimer(hWnd,ID_TIMER,100,NULL);
                break;
        
  3. WM_PAINT: で g_CNT の値を画像を使って描画します。
    数字の画像は1文字が 32*64 で、6桁で表示しています。
    Show() のパラメータは、Sprite 番号,X座標,Y座標の順に指定します。
            int         i,val,v;
            case WM_PAINT:
                hdc= BeginPaint(hWnd,&ps);
                for(i=0,val=g_CNT; i<6; i++)
                {   v= val%10;
                    App->Show(v,(5-i)*32+10,0);
                    val/= 10;
                }
                EndPaint(hWnd, &ps);
                break;
        
  4. WM_TIMER: でキーをスキャンしてカウンタを操作します。
    「横一列に並んだ数字キー(1~5)」で操作して下さい。テンキーでは操作できません。
    ESC キーでプログラムを終了します。
            case WM_TIMER:
                if (GetAsyncKeyState(VK_ESCAPE)<0)
                {     PostMessage(hWnd,WM_CLOSE,0,0);
                      return 0;
                }
                if (GetKeyState('1')< 0)    g_CNT += 10000;
                if (GetKeyState('2')< 0)    g_CNT += 1000;
                if (GetKeyState('3')< 0)    g_CNT += 100;
                if (GetKeyState('4')< 0)    g_CNT += 10;
                if (GetKeyState('5')< 0)    g_CNT += 1;
                InvalidateRect(hWnd,NULL,TRUE);
                break;
        
  5. WM_DESTROY: ではタイマを止めて Object Class を開放して下さい。
             case WM_DESTROY:
                KillTimer(hWnd,ID_TIMER);
                SAFE_DELETE(App);
                PostQuitMessage(0);
                return 0L;
        

【演習】

  1. SPRITE Class または、これに代わる Class を作成してプログラムを完成させて下さい。
    Basic Sprite Class Basic Sprite Object Class が完成 を利用することも出来ます。
  2. InvalidateRect() の TRUE を FALSE に設定すると、カウンタの表示はどうなるでしょう。
  3. Object Class の継承は便利ですが、多用は禁物です。
    多用するとプログラムの細部が見え難くなり、実行の流れを掌握できず、デバッグが困難になります。

【メモ】

スーパークラス(継承元のクラス)で宣言されている関数を、新たに定義することをオーバーライドと言います。
オーバーライドされる可能性のある関数は virtual 宣言をして下さい。
virtual 宣言されていない関数をオーバーライドしてもスーパークラスの関数が呼び出されます。
virtual ~BMP(); //Destructor
virtual void Adjust(BOOL flag=TRUE);

超初心者のプログラム入門(Win32API C++)