list で弾丸を一括して管理する



STL(Standard Template Library) の list を使って弾丸の動きを一括して管理します。
数字キーの「0~3」を押し続けると、キーに対応した弾丸を機関銃のように連射します。
C#でも 弾丸を一括管理 を作成しています。

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

プログラムの説明

  1. STL の list を使うときは list をインクルードして下さい。
    My.lib に登録された Object Class を使っているので my.h を取り込んで my.lib をリンクして下さい。
    ID_TIMER は弾丸を移動するタイマのIDで、ID_TIMER1 は弾を登録するタイマのIDです。
    SHOT は弾丸の動きを管理する構造体です。
    構造体の説明と STL の基礎は list を使って弾丸の動きを管理する を参照して下さい。
    *Back は BACKBUF Object Class の定義です。
    *Img は弾の画像を表示する IMAGE Object Class の定義です。
    このプログラムでは、なるべくシンプルに仕上げるために背景画像の表示は行っていません。
        /****************************************/
        /*★ list で弾丸を管理する    前田 稔 ★*/
        /****************************************/
        #define     NAME    "STL Shoot"
        #include    <windows.h>
        #include    <list>
        #include    "my.h"
        #define     SAFE_DELETE(p)  { if (p) { delete (p);     (p)=NULL; } }
        #define     ID_TIMER    (WM_APP + 0)
        #define     ID_TIMER1   (WM_APP + 1)
        #pragma     once
        #pragma     comment(lib,"my.lib")
    
        using namespace std;
        typedef struct
        {   int     n;                  //弾の種別
            float   x,y;                //弾の座標
            float   dx,dy;              //弾の移動量
        }   SHOT;
        list<SHOT>              v;
        list<SHOT>::iterator    p,q;
        SHOT                    wk;
    
        BACKBUF     *Back= NULL;        //Back Buffer Object
        IMAGE       *Img= NULL;         //Image Object Class
        
  2. WM_CREATE: で Object を生成して弾の画像を入力します。
    tama4.gif が弾丸の画像で、4種類の色が異なる画像が横方向に並んでいます。
    背景画像のスクロールと弾を発射するタイマの間隔を設定します。
            case WM_CREATE:
                Back= new BACKBUF(hWnd);
                Img= new IMAGE(hWnd);
                Img->LoadFile("tama4.gif",4,1);
                SetTimer(hWnd,ID_TIMER,20,NULL);
                SetTimer(hWnd,ID_TIMER1,200,NULL);
                break;
        
  3. WM_TIMER: には二種類のタイマがポストされます。
    ShotMove() で list に登録された弾丸の座標を更新します。
    ID_TIMER1 でキーの押し下げを調べて list に弾丸を登録します。
    ShotAdd() が登録する関数で、引数は Sprite の番号です。
    WM_PAINT: から描画するとチラツクので WM_TIMER: から直接描画します。
    ShotView() が list に登録された弾丸を描画する関数です。
            case WM_TIMER:
                if (wParam == ID_TIMER)  ShotMove();
                if (wParam == ID_TIMER1)
                {   if (GetAsyncKeyState(VK_NUMPAD0)<0)    ShotAdd(0);
                    if (GetAsyncKeyState(VK_NUMPAD1)<0)    ShotAdd(1);
                    if (GetAsyncKeyState(VK_NUMPAD2)<0)    ShotAdd(2);
                    if (GetAsyncKeyState(VK_NUMPAD3)<0)    ShotAdd(3);
                }
                ShotView();
                break;
        
  4. WM_DESTROY: ではタイマを止めてオブジェクトを開放して下さい。
            case WM_DESTROY:
                KillTimer(hWnd,ID_TIMER1);
                SAFE_DELETE(Img);
                SAFE_DELETE(Back);
                PostQuitMessage(0);
                return 0L;
        
  5. list に弾を登録する ShotAdd() 関数です。
    wk.n には描画する Sprite の番号を格納しています。
    list の基礎は list を使って弾丸の動きを管理する を参照して下さい。
        void  ShotAdd(int no)
        {
            ZeroMemory(&wk,sizeof(wk));
            wk.n= no;
            wk.y= 100+no*50;
            wk.dx= 8;
            v.push_back(wk);
        }
        
  6. list に登録された弾を描画する ShotView() 関数です。
    BackBuf を LTGRAY_BRUSH でクリアして Img Class で Sprite を描画します。
        void  ShotView()
        {
            Back->Clear((HBRUSH)GetStockObject(LTGRAY_BRUSH));
            for(p=v.begin(); p!=v.end(); p++)
                Img->Show(Back->hBackDC,p->n,p->x,p->y);
            Back->Blt();
        }
        
  7. list に登録された弾を移動する ShotMove() 関数です。
    弾の座標に dx, dy の値を加えて座標を移動します。
    今回は弾は右方向に動くだけなので、X座標が500を超えたら削除しています。
        void  ShotMove()
        {
            for(p=v.begin(); p!=v.end(); p++)
            {   p->x+= p->dx;
                p->y+= p->dy;
                if(p->x>500.0f)         //500 を超えたら削除
                {   q= p;
                    p--;
                    v.erase(q);
                }
            }
        }
        

【演習】

  1. 右方向だけで無く、四方八方に弾丸を動かしてみて下さい。
  2. 矩形範囲を設定して、画面の外に出た弾を削除して下さい。

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