平滑的人物走動 —— 解決閃屏

本文由BlueCoder編寫   轉載請說明出處:

http://blog.csdn.net/crocodile__/article/details/11581641

我的郵箱:[email protected]    歡迎大家和我交流編程心得

我的微博:BlueCoder_黎小華    歡迎光臨^_^




今天咋一看,發現很久沒寫博客了

的確,開學之後,寫博客的時間越來越少了……

 

今天來做一個比較實用的小應用——平滑的人物走動,同時解決常見的閃屏問題、實現透明位圖

這些技術在遊戲開發中是很常見的

 

------------------------------------------------------------------------------------------------------------------------------------------------------------------------

------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

一、爲了對比效果差異,我們先就用之前講過的BitBlt函數來直接貼位圖

先來看一看一些主要的代碼:

變量說明:

static HBITMAP	hBk, hBmp;			//背景、人物位圖句柄
static SIZE		sBk, sBmp, sClient;	//背景、人物位圖大小 , 客戶區大小
static POINT	ptBmp;				//人物位圖位置


在WM_CREATE消息中做一些初始化工作:

case WM_CREATE:
	{
		//加載位圖資源
		BITMAP	bmp;
		hBmp = LoadBitmap(((LPCREATESTRUCT)lParam)->hInstance, MAKEINTRESOURCE(IDB_BITMAP1));
		hBk = LoadBitmap(((LPCREATESTRUCT)lParam)->hInstance, MAKEINTRESOURCE(IDB_BITMAP2));

		GetObject(hBmp, sizeof(BITMAP), &bmp);
		sBmp.cx	= bmp.bmWidth;
		sBmp.cy	= bmp.bmHeight;

		GetObject(hBk, sizeof(BITMAP), &bmp);
		sBk.cx	= bmp.bmWidth;
		sBk.cy	= bmp.bmHeight;
	}
	//初始化人物位置
	ptBmp.x	= 100;
	ptBmp.y	= 100;
	return 0;


在WM_SIZE消息中獲取客戶區大小

case WM_SIZE:
	sClient.cx	= LOWORD(lParam);
	sClient.cy	= HIWORD(lParam);
	return 0;


在WM_PAINT消息中繪製位圖

case WM_PAINT:
	hdc = BeginPaint(hwnd, &ps);

	hdcMem = CreateCompatibleDC(hdc);
	SelectObject(hdcMem, hBk);

	//由於背景圖片可能超過客戶區大小 , 故採取縮放模式顯示背景圖片
	SetStretchBltMode(hdc, COLORONCOLOR);
	StretchBlt(hdc, 0, 0, sClient.cx, sClient.cy,
		hdcMem, 0, 0, sBk.cx, sBk.cy, SRCCOPY);

	//繪製人物位置
	SelectObject(hdcMem, hBmp);
	BitBlt(hdc, ptBmp.x, ptBmp.y, sBmp.cx, sBmp.cy,
		hdcMem, 0, 0, SRCCOPY);
	DeleteDC(hdcMem);
	EndPaint(hwnd, &ps);
	return 0;

在WM_MOUSEMOVE消息中控制人物位置

//鼠標移動時,這個消息會發送很多,
//因此用它來檢驗閃屏效果是很理想的
case WM_MOUSEMOVE:
	ptBmp.x	= LOWORD(lParam);
	ptBmp.y	= HIWORD(lParam);

	InvalidateRect(hwnd, NULL, TRUE);
	return 0;

 

下面是BitBlt函數的實現效果:(可以發現人物周邊出現了白色區域)

 

 

可見這和實際遊戲中是有差別的

 

二、實現位圖的透明

實現之前,先來看一看一個win32 sdk中的含api函數TransparentBlt

msdn:

BOOL TransparentBlt(
  HDC hdcDest,        // handle to destination DC
  int nXOriginDest,   // x-coord of destination upper-left corner
  int nYOriginDest,   // y-coord of destination upper-left corner
  int nWidthDest,     // width of destination rectangle
  int hHeightDest,    // height of destination rectangle
  HDC hdcSrc,         // handle to source DC
  int nXOriginSrc,    // x-coord of source upper-left corner
  int nYOriginSrc,    // y-coord of source upper-left corner
  int nWidthSrc,      // width of source rectangle
  int nHeightSrc,     // height of source rectangle
  UINT crTransparent  // color to make transparent
);

 

前10個參數和BitBlt的差不多,不用多解釋。主要是最後一個參數crTransparent,當前位圖中需要透明的顏色(一般都是白色或者黑色)

==> 因此,你應該保證非透明區域不能包含透明顏色,否則會有一定的出入

另外還需要注意的一點:Transparent函數只適合低於32位色位圖的透明,當然常見的都是RGB原色——24位的,因此它是夠用的

 

只需要將WM_PAINT中的BitBlt換成Transparent就能實現久違的位圖透明效果

TransparentBlt(hdc, ptBmp.x, ptBmp.y, sBmp.cx - 10, sBmp.cy - 10, 
	hdcMem, 0, 1, sBmp.cx, sBmp.cy - 1, RGB(255, 255, 255));

 

下面就是實現效果:

 

可以發現,透明效果是實現了,但是閃屏確實很厲害……

 

三、解決閃屏問題

要解決問題,需要知道問題的根源所在:

各位還記得WNDCLASS這個類型的結構體變量嗎?

它在註冊窗口前需要初始化,我們來看看初始化代碼:       

wndclass.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);

對,問題就出現在這裏,我們設置了背景刷爲白色的刷子,那麼當你重繪客戶區的時候,程序就會使用你默認設定的這個白色刷子來刷背景,由於鼠標移動消息很頻繁,因此就會看到很厲害的閃屏

 

那麼,解決方法就很簡單了,主要有兩種方式:

(1)將背景刷設定爲NULL,空刷子——透明的刷子

wndclass.hbrBackground	= NULL;

 

(2)不改變背景刷(依然使用白色背景刷子),只是在試窗口無效時,我們選擇不重繪背景,具體就是將InvalidateRect的最後一個參數設定爲FALSE

case WM_MOUSEMOVE:
	ptBmp.x	= LOWORD(lParam);
	ptBmp.y	= HIWORD(lParam);

	InvalidateRect(hwnd, NULL, FALSE);//這裏設爲FALSE
	return 0;

 

ok,來看看解決後的效果:

 

可見頻繁的閃屏解決了^_^

 

------------------------------------------------------------------------------------------------------------------------------------------------------------------------

------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

今天到此爲止吧(如果各位需要源代碼或者相應資源,可以評論留下郵箱,我會發給你^_^)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章