BG を二枚重ねる

BG を二枚重ねて、その間にキャラクタを置くことにより、背景に奥行きを持たせます。

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

プログラムの説明

  1. BG に使用する一般的な画像と、透けて見える部分に透明色(黒)を設定した上から重ねる画像です。
    通路や草原の上から、花や木の背景を透明にした画像を重ねて、二枚の BG の間を通るように描画します。

  2. BG も工夫次第で、例えば上と下の BG のスクロール速度を変えて遠近感を持たせたり、三枚以上の BG を 組み合わせて、より立体感を持たせることが出来ます。
    またゲームの進行状況によりマップチップを変える方法もあります。
    例えば、最初は宝箱が閉じていますが、宝を取ると蓋が開いた画像に切り替えたりします。
  3. 私有ライブラリを使うので my.lib をリンクします。
    V_HLIMIT, H_HLIMIT はキャラクタが画面の端に来たときに BG のスクロールを始める閾値(しきいち)です。
    Bg が下の BG Class で Bgu が上から重ねる BG Class です。
    キャラクタの移動や背景のスクロールは前のページを参照して下さい。
    Att[] では木の裏側を通るので、透明色を設定した木の BG に対して「通行可能」を設定しています。
        /*****************************************************/
        /*★ BG(Back Ground) Double    2006-01-17  前田 稔 ★*/
        /*****************************************************/
        #include    <windows.h>
        #include    "Bg.h"
        #pragma     once
        #pragma     comment(lib,"my.lib")
        #define     ID_TIMER    (WM_APP + 0)
        #define     WIDTH       640
        #define     HEIGHT      480
        #define     W_LIMIT     (WIDTH-40)
        #define     H_LIMIT     (HEIGHT-40)
    
        BACKBUF     *Back= NULL;        //Back Buffer Object
        BG          *Bg= NULL;          //Back Ground Object
        BG          *Bgu= NULL;         //Back Ground Object Upper
        GSPRITE     *Char= NULL;        //Charcter Object
        WORD        g_xp, g_yp;         //キャラクタの座標
        WORD        xoff=0, yoff=0;     //背景のスクロール値
        WORD        g_n= 0;             //進行方向(0 ~ 3)
        WORD        g_chg= 0;           //画像切り替えフラグ
        int         Att[256];           //Mapchip の属性
        
  4. Back Class, Bg Class に続いて Bgu Class を設定します。
    GSPRITE Class は My.lib に登録されている GIF 画像を使った Sprite Class です。
    Double.csv, Double2.csv は Mapedit で保存した BG 情報が記録されている TEXT 形式のファイルです。
    Mapchip に使用する画像ファイルの名前や BG のサイズや Mapchip の並び情報が記録されています。
    拡張子 csv は Comma Separated Value の略で、項目をカンマで区切りレコードを改行で区切るフォーマットです。
    Map2att.txt は Mapchip の属性(通れる/通れない)が記録された TEXT 形式のファイルです。
            case WM_CREATE:
                Back= new BACKBUF(hWnd);
                Bg= new BG(hWnd);
                Bg->SetCsv("Double.csv");
                Bg->SetTable("MapSatt.txt",Att,256);
                Bgu= new BG(hWnd);
                Bgu->SetCsv("Double2.csv");
                Char= new GSPRITE(hWnd);
                Char->Load("chr17.gif",1,8);
                g_xp=g_yp= 200;
                Back->SetMode(WIDTH,HEIGHT,32);
                SetTimer(hWnd,ID_TIMER,100,NULL);
                break;
        
  5. キャラクタの移動を設定する関数です。
    現在表示されている背景上ではキャラクタだけを動かし、画面の端にきたときに背景をスクロールします。
    キャラクタの基準座標は左上で、サイズが 32*32 なので +16, +12 を加えて座標を調整します。
    それでも実際に動かすと上下左右で微妙に異なるので、移動方向により微調整が必要です。
    最初に Upper のマップチップを調べて、透明セルのとき Lower のセルを調べます。
    セルの属性 Att[ChipNo] が 1 のときにキャラクタが通ることができます。
    キャラクタの移動は「8 ~ H_HLIMIT と 8 ~ V_HLIMIT」の空間に制限していますが、ゲームによって自由に設定して下さい。
        void  move()
        {   int     xp,yp;
            int     ChipNo;
    
            yp= g_yp+16;
            xp= g_xp+12;
            switch(g_n)
            {   case 0: yp-= 8;  break; //上
                case 1: xp+= 8;  break; //右
                case 2: yp+= 16; break; //下
                case 3: xp-= 8;  break; //左
            }
            //Upper の ChipNo
            ChipNo= Bgu->Chip(xp+xoff,yp+yoff);
            //Upper が透明セルのとき
            if (ChipNo==0)  ChipNo= Bg->Chip(xp+xoff,yp+yoff);
            if (ChipNo==-1)     return;
            if (Att[ChipNo]!=1) return;
            switch(g_n)
            {   case 0:      //上
                    g_yp-= 2;
                    if (g_yp<8)
                    {   if (yoff>0)     yoff-= 2;
                        g_yp= 8;
                    }
                    break;
                case 1:     //右
                    g_xp+= 2;
                    if (g_xp>H_HLIMIT)
                    {   xoff+= 2;
                        g_xp= H_HLIMIT;
                    }
                    break;
                case 2:     //下
                    g_yp+= 2;
                    if (g_yp>V_HLIMIT)
                    {   yoff+= 2;
                        g_yp= V_HLIMIT;
                    }
                    break;
                case 3:     //左
                    g_xp-= 2;
                    if (g_xp<8)
                    {   if (xoff>0)     xoff-= 2;
                        g_xp= 8;
                    }
                    break;
            }
        }
        
  6. キャラクタ座標の微調整はメインプログラムで行うので Chip() メンバ関数では座標をそのまま判定しています。
        // MapChip の番号を返す
        int  BG::Chip(int xp, int yp)
        {   int     x,y,off;
    
            x= xp>>4;
            y= yp>>4;
            if (x>=XN || y>=YN || x<0 || y<0)   return -1;
            off= y*XN+x;
            return *(MAP+off);
        }
        
  7. BG とキャラクタを描画する Render() 関数です。
    最初に下の BG を描画して、キャラクタを描画してから上の BG を描画します。
        VOID  Render()
        {   Back->Clear((HBRUSH)GetStockObject(LTGRAY_BRUSH));
            Bg->View(Back->hBackDC,xoff,yoff);
            Char->Show(Back->hBackDC,g_n*2+g_chg,g_xp,g_yp);
            Bgu->View(Back->hBackDC,xoff,yoff);
            Back->Blt();
        }
        

【演習】

  1. Full Screen Mode に設定してプログラムを完成させて下さい。
  2. 二枚の GB の間でキャラクタを描画して立体感を持たせて下さい。
  3. 次の方法でスクロールして下さい。

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