画像を5枚に分割して描画する

VC++ で Sprite を5枚並べた画像を切り出して、透明色を設定して描画します。

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

プロジェクトの設定

  1. 空のプロジェクトを作成して、次のファイルを格納して下さい。
    画像は 400×96×8bit を使っていますが、別の画像でも構いません。
    画像の仕様が違うときは、画像に合わせてプログラムを修正して下さい。
    Main.cpp メインプログラム
    Ene5.bmp 背景を黒で塗りつぶした5枚の Enemy を横に並べたファイル
  2. Main.cpp を [プロジェクト][既存項目の追加] からプロジェクトに追加します。
    画像は BMP ファイルから直接入力します。
  3. ビルドに続いて実行を行います。
    ページ先頭の画像のように、ウインドウに画像が表示されたら完成です。

プログラムの説明

  1. CommonControls を使うときは commctrl.h を取り込んで COMCTL32.LIB をリンクして下さい。
    hImage が Image List の定義です。
        #include    <windows.h>
        #include    <commctrl.h>
        #pragma     comment(lib,"comctl32.lib")
    
        HINSTANCE   g_hInst;
        HWND        g_hWnd;
        HIMAGELIST  hImage;
        
  2. WinMain() は何時もと同じでウインドウを表示するだけです。
    WM_CREATE も前回と同じです。
    WM_DESTROY も前回と同じです。
  3. WM_PAINT: では5枚の画像を ImageList_Draw() で表示します。
            case WM_PAINT:
                hdc = BeginPaint(hWnd, &ps);
                for(i=0; i<5; i++)
                    ImageList_Draw(hImage,i,hdc,i*100+20,20,ILD_NORMAL);
                EndPaint(hWnd, &ps);
                break;
        
  4. Image List を生成して画像を登録する関数 AppInit() です。
    ImageList_Create() で Image List を生成します。
    80,96 が画像のサイズで、ILC_COLOR8 が256色の指定で ILC_MASK が透明色を使用するフラグです。
    BMP 画像のサイズは 400×96×8bit で、5枚の画像が横に並んでいることに注目して下さい。
    5が登録する枚数で、最後のパラメータにはゼロを指定して下さい。
    LoadImage() でファイルから画像を入力します。
    ImageList_AddMasked() で黒を透明色 RGB(0,0,0) に設定して Image List に登録します。
    このとき指定された画像の幅が Image List より大きいと自動的に切り分けられます。
    高さも切り分けてくれると有り難いのですが、残念ながら無視されてしまいました。
        void  AppInit()
        {   HBITMAP     hBmp;
            hImage = ImageList_Create(80,96,ILC_COLOR8 | ILC_MASK,5,0);
            hBmp= (HBITMAP)LoadImage(NULL,"Ene5.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
            if (ImageList_AddMasked(hImage,hBmp,RGB(0,0,0))==-1)
                MessageBox(NULL,"ImageList_AddMasked Error","Image List",MB_OK);
            DeleteObject(hBmp);
        }
        
  5. ImageList_Create() 関数の仕様です。
    HIMAGELIST ImageList_Create(
        int cx,     
        int cy,     
        UINT flags,     
        int cInitial,     
        int cGrow    
       );
    
    cxはイメージの幅、cyは高さを指定します。
    flagsは、イメージリストのタイプで ILC_COLOR がデフォルトです。
    マスクを使用するときは ILC_MASK を加えます。
    cInitialは、リスト中のイメージ数の初期値です。
    cGrowは、新しいイメージのための領域を作るためにシステムがリストをリサイズするためのイメージの数です。
    戻り値はイメージリストハンドル(HIMAGELIST)です。
  6. C# でも同様のプログラムを作成していますが、Image List 自体に画像を切り分ける機能は見当たりません。
    C# Image List は 画像を分割して登録 を参照して下さい。

【全ソースコード】

/*★ Image List で透明色を使用する     前田 稔 ★*/
#define     NAME    "Color Key"
#define     STRICT
#include    <windows.h>
#include    <commctrl.h>
#pragma     comment(lib,"comctl32.lib")

HINSTANCE   g_hInst;
HWND        g_hWnd;
HIMAGELIST  hImage;

//★ アプリケーションの初期化
void  AppInit()
{   HBITMAP     hBmp;
    hImage = ImageList_Create(80,96,ILC_COLOR8 | ILC_MASK,5,0);
    hBmp= (HBITMAP)LoadImage(NULL,"Ene5.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
    if (ImageList_AddMasked(hImage,hBmp,RGB(0,0,0))==-1)
        MessageBox(NULL,"ImageList_AddMasked Error","Image List",MB_OK);
    DeleteObject(hBmp);
}

//★ CALLBACK 関数
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{   PAINTSTRUCT ps;
    HDC         hdc;
    int         i;

    switch(msg)
    {   case WM_CREATE:
            InitCommonControls();
            AppInit();
            break;
        case WM_PAINT:
            hdc = BeginPaint(hWnd, &ps);
            for(i=0; i<5; i++)
                ImageList_Draw(hImage,i,hdc,i*100+20,20,ILD_NORMAL);
            EndPaint(hWnd, &ps);
            break;
        case WM_DESTROY:
            ImageList_Destroy(hImage);
            PostQuitMessage(0);
            return 0L;
        default:
            return (DefWindowProc(hWnd, msg, wp, lp));
    }
    return 0L;
}

//★ Windows Main 関数
int APIENTRY  WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int nCmdShow)
{   MSG         msg;

    g_hInst= hInst;
    WNDCLASS wc = { CS_CLASSDC,WndProc,0L,0L,hInst,NULL,LoadCursor(NULL,IDC_ARROW),
                    (HBRUSH)GetStockObject(GRAY_BRUSH),NULL,NAME };
    if (RegisterClass(&wc)==0)    return FALSE;
    g_hWnd= CreateWindow(NAME,NAME,WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT,CW_USEDEFAULT,520,180,
            NULL,NULL,hInst,NULL);
    if (!g_hWnd)  return FALSE;

    ShowWindow(g_hWnd,nCmdShow);
    UpdateWindow(g_hWnd);
    SetFocus(g_hWnd);
    while (GetMessage(&msg,NULL,0,0))
    {   TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return S_OK;        //return 0
}

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