簡単なアニメーションやゲームなどを作成したとき、キャラクタの数が多いと画面がちらつく事があります。
この解決策と具体的な便利関数と使い方を紹介します。
以前に「ダブル・バッファリングの方法(1)」と「ダブル・バッファリングの方法(2)」で紹介した関数バージョンです。
ここで紹介する便利関数は次の3つです。
- funcCreateMemDC()
- funcDeleteMemDC()
- funcGetSizeMemDC()
プロトタイプ宣言
HDC CreateCompatibleDC( HDC hDC // デバイスコンテキストのハンドル ); HBITMAP CreateCompatibleBitmap( HDC hDC, // デバイスコンテキストのハンドル int nWidth, // ビットマップの横幅 int nHeight // ビットマップの高さ );
オフ・スクリーンの作成
extern HDC funcCreateMemDC( HDC hDC, LONG sx, LONG sy, DWORD dwRop ) { HDC hMemDC; HBITMAP hBitmap; hMemDC = CreateCompatibleDC( hDC ); hBitmap = CreateCompatibleBitmap( hDC, sx, sy ); SelectObject( hMemDC, hBitmap ); SelectObject( hMemDC, GetStockObject(DC_PEN) ); SelectObject( hMemDC, GetStockObject(DC_BRUSH) ); DeleteObject( hBitmap ); if ( dwRop != 0 ){ PatBlt( hMemDC, 0, 0, sx, sy, dwRop ); } return hMemDC; }
オフ・スクリーンの破棄
extern BOOL funcDeleteMemDC( HDC hMemDC ) { return DeleteDC( hMemDC ); }
オフ・スクリーンのサイズ取得
extern BOOL funcGetSizeMemDC( HDC hMemDC, LONG *sx, LONG *sy ) { HGDIOBJ hBitmap; BITMAP BmpInfo; if ( (hBitmap = GetCurrentObject(hMemDC,OBJ_BITMAP)) != NULL ){ GetObject( hBitmap, sizeof(BITMAP), &BmpInfo ); *sx = BmpInfo.bmWidth; *sy = BmpInfo.bmHeight; return TRUE; } return FALSE; }
使い方
//------------------------------------------------ // break付きのキーワード //------------------------------------------------ #define CASE break;case #define DEFAULT break;default //------------------------------------------------ // 記号定数 //------------------------------------------------ #define MAX_WIDTH (640) #define MAX_HEIGHT (480) //------------------------------------------------ // ウインドウのプロシージャ関数 //------------------------------------------------ LRESULT CALLBACK mainWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { static HDC hMemDC; switch ( uMsg ){ CASE WM_CREATE: { HDC hDC; // DCコンパチブルの作成 hDC = GetDC( hWnd );hMemDC = funcCreateMemDC( hDC, MAX_WIDTH, MAX_HEIGHT, WHITENESS );ReleaseDC( hWnd, hDC ); } CASE WM_CLOSE: // DCコンパチブルの破棄funcDeleteMemDC( hMemDC );DestroyWindow( hWnd ); CASE WM_DESTROY: PostQuitMessage( 0 ); CASE WM_PAINT: { HDC hDC; PAINTSTRUCT ps; LONG sx; LONG sy; // DCコンパチブルの描画 hDC = BeginPaint( hWnd, &ps );funcGetSizeMemDC( hMemDC, &sx, &sy );BitBlt( hDC, 0, 0, sx, sy, hMemDC, 0, 0, SRCCOPY ); EndPaint( hWnd, &ps ); } CASE WM_ERASEBKGND: // 何も処理しない⇒塗り潰した return 1; CASE WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: { UINT cx = (SHORT)LOWORD(lParam); UINT cy = (SHORT)HIWORD(lParam); SetDCPenColor( hMemDC, RGB(0xFF,0xFF,0x00) ); SetDCBrushColor( hMemDC, RGB(0x00,0x00,0xFF) ); Rectangle( hMemDC, cx, cy, (cx + 16*5), (cy + 16*3) ); InvalidateRect( hWnd, NULL, FALSE ); UpdateWindow( hWnd ); } CASE WM_RBUTTONUP: PatBlt( hMemDC, 0, 0, MAX_WIDTH, MAX_HEIGHT, WHITENESS ); InvalidateRect( hWnd, NULL, FALSE ); UpdateWindow( hWnd ); DEFAULT:return DefWindowProc( hWnd, uMsg, wParam, lParam ); } return 0; }
解説
- WM_CREATEメッセージで funcCreateMemDC() 関数によりオフ・スクリーンを作成してます。
- WM_CLOSEメッセージで funcDeleteMemDC() 関数によりオフ・スクリーンを破棄してます。
- WM_PAINTメッセージで funcGetSizeMemDC() 関数によりオフ・スクリーンのサイズを取得してます。
- WM_LBUTTONDOWNメッセージなどで長方形をオフ・スクリーンに描画してWM_PAINTメッセージで再描画させます。
- WM_RBUTTONUPメッセージでオフ・スクリーンを消去してます。
> 無謀にもプログラム言語など作ろうとしてる底辺プログラマでございます。
良いですね。
私も昔(1998年)にゲーム言語を製作しました。
ドラクエ風のRPGゲームで処理するゲーム言語(スクリプト言語)です。
> この度ちらつき防止の勉強をしていたところ、ここに行き着きました。
そうでしたか。
> 方法1.2.そしてこのページの関数型と3つ見ましたが、
> ここの方法が一番自分のところに合ってる気がしますので使わせていただきますね。
どうぞ。
C++を知ってるのならばクラスと作成すると便利ですよ。
方法1.2.そしてこのページの関数型と3つ見ましたが、ここの方法が一番自分のところに合ってる気がしますので使わせていただきますね。