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