今回作成するアニメーションは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 に格納されています。
タイムアウト値を変えるようなアニメーションにはスレッドを使いましょう。
★☆ ダウンロード ☆★