パラパラアニメーション

概要:BMPファイルを使った簡単なパラパラアニメーション

今回作成するアニメーションはGIFアニメのような、
単純に表示する画像を切り替えていくだけのアニメーションです。

■画像の準備

それぞれのフレームを別々のファイルとして用意しても構いませんが、
スマートにアニメーションを実現したいならば、
フィルムのように全てのフレームを繋げた一枚の画像を用意しましょう。
それぞれのフレームのサイズは全て同じにします。

今回は左から右に全てのフレームが順番に並んだ一枚の画像について話を進めていきます。

私が用意したフィルムはGIFアニメーションをばらして繋げただけです。

■アニメーション

上に示したフィルムをアニメーションさせるには、左のフレームから順番に表示させれば良さそうです。
ま、普通のフィルムとフレームの使い方ですね。

BitBlt 関数や StretchBlt 関数には「コピー元長方形の左上隅の x 座標」を指定する引数がありました。
全てのフレームサイズは同じなのですから、どこから読み始めるかを変えていけば、
異なるフレームを表示させる事ができます。

BOOL BitBlt(
  HDC hdcDest,   // コピー先デバイスコンテキストのハンドル
  int nXDest,     // コピー先長方形の左上隅の x 座標
  int nYDest,     // コピー先長方形の左上隅の y 座標
  int nWidth,     // コピー先長方形の幅
  int nHeight,     // コピー先長方形の高さ
  HDC hdcSrc,    // コピー元デバイスコンテキストのハンドル
  int nXSrc,      // コピー元長方形の左上隅の x 座標
  int nYSrc,      // コピー元長方形の左上隅の y 座標
  DWORD dwRop  // ラスタオペレーションコード
);

#define FRAME_WIDTH     109
#define FRAME_HEIGHT    109

static HDC hMemDC;
static frame_num;

BitBlt(hdc,0,0,FRAME_WIDTH,FRAME_HEIGHT,hMemDC,FRAME_WIDTH*frame_num,0,SRCCOPY);

フレームのサイズや総数はあらかじめ調べておきます。
frame_num はフレームの番号です。

■タイマー

アニメーションするには、時間が経過する毎にフレーム番号を変えなければなりませんが、
今回は単純なパラパラアニメーションなので、タイマーで十分です。
要求により処理を一時停止させたり、分岐させたり、特別なフレームを挿入したりするような状況は考慮しません。
そのような複雑なアニメーションを行うにはスレッドを利用する事になります。

タイマーで行うべき事は、フレーム番号の変更、再描画メッセージの発行、だけです。

それでは、全体のプログラムをご覧下さい。
FRAME_WIDTH , FRAME_HEIGHT はフレームのサイズ、FRAME_SUM はフレームの総数です。

#define FRAME_WIDTH     109
#define FRAME_HEIGHT    109
#define FRAME_SUM       13

LRESULT CALLBACK WindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    HBITMAP hBitmap;
    static HDC hMemDC;
    static frame_num;

    switch(uMsg) {
        case WM_CREATE:
            hBitmap=(HBITMAP)LoadImage(0,"butterfly.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
            hMemDC=CreateCompatibleDC(NULL);
            SelectObject(hMemDC,hBitmap);
            DeleteObject(hBitmap);
            //タイマー設定
            SetTimer(hWnd,1,100,NULL);
            return 0;
        case WM_DESTROY:
            DeleteDC(hMemDC);
            PostQuitMessage(0);
            return 0;
        case WM_TIMER:
            if(++frame_num >= FRAME_SUM) frame_num=0;
            InvalidateRect(hWnd,NULL,FALSE);
            return 0;
        case WM_PAINT:
            hdc=BeginPaint(hWnd,&ps);
            //表画面へ転送
            BitBlt(hdc,0,0,FRAME_WIDTH,FRAME_HEIGHT,hMemDC,FRAME_WIDTH*frame_num,0,SRCCOPY);
            EndPaint(hWnd,&ps);
            return 0;
    }
    return DefWindowProc(hWnd,uMsg,wParam,lParam);
}

複数個のアニメーションを違うフレームレート(タイムアウト値)で並列実行させたい場合は、
タイマの識別子によって WM_TIMER の処理を分岐させればいいでしょう。
タイマ識別子は WM_TIMER の WPARAM に格納されています。

タイムアウト値を変えるようなアニメーションにはスレッドを使いましょう。

★☆ ダウンロード ☆★


戻る / ホーム