目パチ、口パクのアニメーション

アニメーション GIF

DirectX の CDisplay Class を使って、部分(部品)を組み合わせてアニメーションを行います。
まだまだ DirectX の2D描画の要望は根強いようなので、シンプルなアニメーションのサンプルプログラムを作成してみました。
このプログラムは DirectX August 2007 を使って開発しました。

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

プログラムの説明

  1. プロジェクトのフォルダーに次のファイルを格納して下さい。
    ファイル名 ファイルの説明
    Main.cpp Main Program File
    Ddutil.cpp c:\Dx90SDK\Samples\C++\Common からコピー
    Ddutil.h c:\Dx90SDK\Samples\C++\Common からコピー
    Dxutil.h c:\Dx90SDK\Samples\C++\Common からコピー
    Kao.bmp 130*130 ドットの顔全体の画像
    Buhin.bmp 3枚の目と3枚の口を縦に並べた画像
    Kao.bmp は下記の画像の左半分で、「幅と高さが共に 130ドット」の顔全体の画像です。
    Buhin.bmp は下記の画像の右半分で、幅が 60ドットで、3枚の目と3枚の口を縦に並べた画像です。
    目の1枚分のサイズは、幅=60,高さ=20 で、口の1枚分のサイズは、幅=60,高さ=30 になっています。

  2. timeGetTime() を使うので mmsystem.h を取り込んで winmm.lib をリンクして下さい。
    g_pSurface1 に顔全体の画像をロードします。
    g_pSurface2 アニメーションに使う目と口の画像をロードします。
    eye[] と mouth[] は目と口を切り替えるタイミングを調整する配列です。
    0,1,2 は、それぞれの Sprite の番号です。
    このテーブルを変更することにより、目と口のタイミングを変えることができます。
    g_num はアニメーションするために、テーブル(eye[], mouth[]) の番号を格納する領域です。
    HWND        g_hWnd;
    CDisplay*   g_pDisplay    = NULL;
    CSurface*   g_pSurface1   = NULL;
    CSurface*   g_pSurface2   = NULL;
    BOOL        g_bActive     = FALSE;
    char        img1[]        = "kao.bmp";      //130*130
    char        img2[]        = "buhin.bmp";    //60*20*3, 60*30*3
    int         eye[16]   = { 0,1,2,0,0,0,0,0,0,1,2,0,0,0,0,0 };
    int         mouth[16] = { 0,0,1,1,2,2,0,0,0,0,1,1,2,2,0,0 };
    int         g_num= 0;                       //スプライトの切り替え
        
  3. Direct Draw の初期化です。
    CreateWindowedDisplay() で DisplayMode を設定します。
    CreateSurfaceFromBitmap() でアニメーションに使う二枚の画像を設定します。
    HRESULT InitDirectDraw(HWND hWnd)
    {   HRESULT     hr;
    
        g_pDisplay = new CDisplay();
        if (FAILED(hr=g_pDisplay->CreateWindowedDisplay(hWnd,320,240)))     return hr;
        if (FAILED(hr=g_pDisplay->CreateSurfaceFromBitmap(&g_pSurface1,img1,0,0)))  return hr;
        if (FAILED(hr=g_pDisplay->CreateSurfaceFromBitmap(&g_pSurface2,img2,0,0)))  return hr;
        return S_OK;
    }
        
  4. 描画は DisplayFrame() 関数で行います。
    timeGetTime() で時刻を取得してスプライトの番号を切り替えます。
    アニメーションの切り替え速度は timeGetTime()/200 の値で調整して下さい。
    最初に顔全体を描画します。
    rect に描画する画像の範囲(1枚のスプライト)を設定して重ね書きします。
    顔の画像に重ねるように目のスプライトを描画します。
    次に口のスプライトを描画します。
    HRESULT DisplayFrame()
    {   HRESULT hr;
        RECT    rect;
    
        g_pDisplay->Clear(RGB(80,100,60));
        g_num= (timeGetTime()/200)%16;
    
        // 顔(g_pSurface1) を描画
        g_pDisplay->Blt(100,50,g_pSurface1,NULL);
        // 目(g_pSurface2) を顔にかぶせる
        SetRect(&rect,0,eye[g_num]*20,60,eye[g_num]*20+20);
        g_pDisplay->Blt(139,100,g_pSurface2,&rect);
        // 口(g_pSurface2) を顔にかぶせる
        SetRect(&rect,0,mouth[g_num]*30+60,60,mouth[g_num]*30+90);
        g_pDisplay->Blt(139,123,g_pSurface2,&rect);
    
        if (FAILED(hr=g_pDisplay->Present()))   return hr;
        return S_OK;
    }
        
  5. マウスカーソルを非表示に設定してみました。
    プログラムを終了するときは、何かキーを押して下さい。
            case WM_KEYDOWN:
                PostMessage(hWnd,WM_CLOSE,0,0);
                return 0L;
            case WM_SETCURSOR:          //カーソルを非表示
                SetCursor(NULL);
                return TRUE;
        

超初心者の方のために全ソースコードを掲載します。 (^_^;)
全ソースコード

超初心者のプログラム入門(DirectX9 game program)