VC++ game(三) 使用双缓冲技术进行绘画

VC++开发游戏不要使用VS2010,不然非常非常的慢,除非用引擎,因为VS2010的升级不是专门为游戏而做的,更加强大的.net功能使得VC++开发游戏非常吃力,用VS2008就好。

首先什么是双缓冲呢?

双缓冲就是除了在屏幕上有图形进行显示以外,在内存中也有图形在模拟绘制。我们可以把要显示的图形先在内存中绘制好,然后再一次性的将内存中的图形按照一个点一个点地覆盖到屏幕上去(这个过程非常快,因为是非常规整的内存拷贝)

一般直接的贴图是将 CDC设备中存的图片输出到dc中,多次执行该操作时会出现刷新闪屏的问题

而双缓冲则是申请另外的 CDC设备,将原来本该输出到 dc中的多个图片定向输出到该缓冲 CDC中,合成一张图后,在拷贝到dc荧幕上去

比如我们要画一个背景图,然后再背景图上绘制一个人物,用键盘控制人物的移动。

而人物的绘制我们采用镂空技术,镂空技术就是去背景色,只显示要显示的对象,就像透明的png格式图片。

镂空技术需要两张图片p1,p2,p1中人物角色内为黑色,背景是白色,p2人物是要显示的样子,背景色是白色。

如图:

右边一部分为p1,左边的一部分为p2,首先p1与背景做与运算,白色为0xFFFFFF黑色为0x000000,这样后小人区域全为0,小人周围还是背景色

然后p2在相同的位置做或运算,这样后小人就显示出来,去掉了背景色。这就是图片镂空技术,alpha通道的实现,使得这种技术慢慢消隐了。

 

如何实现双缓冲呢?我们需要准备以下工作:

1:两个CDC  :cDc 用于选择图片资源   bufferCDC 用于将要绘画的图片组合在一起,然后再显示到设备上。

2:一个缓冲CBitmap   

 

ok,代码如下,如果你看了第一个VC++ game(开场篇),那么只需改动里面的MyWnd.cpp文件

以下代码的实现功能是通过键盘左右方向键控制小人移动,当超出屏幕,小人停止移动。

通过定时器定时刷新屏幕,定时器的添加和绘画函数添加一样,在类视图界面选择MyWnd.cpp,点击右键选择属性,在消息中添加OnTimer.

具体代码实现如下:

MyWnd.cpp:

 

// MyWnd.cpp : 实现文件
//

#include "stdafx.h"
#include "MyWnd.h"
#define WIDTH 800
#define HEIGHT 600

// CMyWnd

IMPLEMENT_DYNCREATE(CMyWnd, CFrameWnd)

CMyWnd::CMyWnd()
: cDc(NULL)
, bacBitmap(NULL)
, perBitmap(NULL)
, perX(720)
, bufferCDC(NULL)
, bufferBitmap(NULL)
{
	Create(NULL,"Double Cash");
	CClientDC dc(this);
	int startX=(dc.GetDeviceCaps(HORZRES)-WIDTH)/2;
	int startY=(dc.GetDeviceCaps(VERTRES)-HEIGHT)/2;
	MoveWindow(startX,startY,WIDTH,HEIGHT);

	
	cDc=new CDC;
	cDc->CreateCompatibleDC(&dc);
	bufferCDC=new CDC;
	bufferCDC->CreateCompatibleDC(&dc);//兼容的DC

	bufferBitmap=new CBitmap;
	bufferBitmap->CreateCompatibleBitmap(&dc,WIDTH,HEIGHT);//兼容的Bitmap
	bufferCDC->SelectObject(bufferBitmap);

	bacBitmap=new CBitmap;
	perBitmap=new CBitmap;

	bacBitmap->m_hObject=(HBITMAP)::LoadImage(NULL,"bac.bmp",IMAGE_BITMAP,800,582,LR_LOADFROMFILE);
	perBitmap->m_hObject=(HBITMAP)::LoadImage(NULL,"per.bmp",IMAGE_BITMAP,98,308,LR_LOADFROMFILE);
	SetTimer(1,100,NULL);
	
}

CMyWnd::~CMyWnd()
{
}


BEGIN_MESSAGE_MAP(CMyWnd, CFrameWnd)
	ON_WM_TIMER()
	ON_WM_KEYDOWN()
END_MESSAGE_MAP()


// CMyWnd 消息处理程序

void CMyWnd::OnTimer(UINT_PTR nIDEvent)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	CClientDC dc(this);
	cDc->SelectObject(bacBitmap);
	bufferCDC->BitBlt(0,0,WIDTH,HEIGHT,cDc,0,0,SRCCOPY);//将背景画到缓冲区
	cDc->SelectObject(perBitmap);

	if(perX%2==0)
	{
		bufferCDC->BitBlt(perX,0,49,154,cDc,49,0,SRCAND);
		bufferCDC->BitBlt(perX,0,49,154,cDc,0,0,SRCPAINT);
	}
	else
	{
		bufferCDC->BitBlt(perX,0,49,154,cDc,49,154,SRCAND);
		bufferCDC->BitBlt(perX,0,49,154,cDc,0,154,SRCPAINT);
	}
	

	dc.BitBlt(0,0,WIDTH,HEIGHT,bufferCDC,0,0,SRCCOPY);

	CFrameWnd::OnTimer(nIDEvent);
}

void CMyWnd::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	if(perX>760||perX<=0)
	{
		KillTimer(1);
		return;
	}
	switch(nChar)
	{
	case VK_LEFT:
		perX--;
		break;
	case VK_RIGHT:
		perX++;
		break;
	default:break;
	}

	CFrameWnd::OnKeyDown(nChar, nRepCnt, nFlags);
}


有不对的地方请大家指正。

有要工程的可以留言。

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值