如果你真正实现动画的话,你会发现画面一闪一闪的,十分的不爽。 很多人都会怪到GDI头上,他们又会骂MS,说GDI太慢了。其实非也(不是指MS不该骂,呵呵),任何直接写屏幕的操作都会产生闪烁,在DOS下 直接写显存或者用DirectDraw API直接写Primary Surface都会闪烁,因为你每个更新显示的操作都会被用户马上看到(因为垂直回扫的原因, 或许会有延迟)。
消除闪烁最简单也是最经典的方法就是双缓冲(Double buffer)。所谓的双缓冲其实道理非常简单,就是说我们在其它地方(简单的说就是不针对屏幕,不显示出来的地方)开辟一个存储空间,我们把所有的动画都要渲染到这个地方,而不是直接渲染到屏幕上(针对屏幕的存储区域)。在GDI中,直接针对屏幕就是窗口DC,”不可见的地方”一般可以用Memory DC。在把所有动画渲染到后台缓冲之后,再一下次整体拷贝到屏幕缓冲区!
在纯软件2D图形引擎中,双缓冲一般意味着在内存中开辟一个区域用来存储像素数据
view类里面创建CDC对象m_ImageMemo,指针m_pDC,创建二者关联,并且通过一个窗口大小的位图来确定内存DC即m_ImageMemo的大小; 将m_ImageMemo以引用的方式传到要画的其他类里面:假设类test1, test2类,类的成员函数里面的画操作只是m_ImageMemo.BitBlt,最后在view类面只要将m_ImageMemo内容拷贝到屏幕上面就可以了,
具体作法:
1.在view类里面创建窗口大小的内存DC m_ImageMemo;
void CGameView::OnInitialUpdate()
{
CView::OnInitialUpdate();
CRect rc;
GetClientRect(rc);
m_ImageMemo.CreateCompatibleDC(m_pDC); //创建二者关联;
//最多只能一次;
CBitmap bmp;
bmp.CreateCompatibleBitmap(m_pDC,rc.Width(),rc.Height());
m_ImageMemo.SelectObject(&bmp);
bmp.DeleteObject() ;
}
其中函数OnInitialUpdate()手动添加,
2.以引用的形式传到test1::Draw(&m_ImageMemo), test2::Draw(&m_ImageMemo);
3.最后将内存DCm_ImageMemo的内容拷贝到屏幕上面,一次性显示;
CRect rc;
GetClientRect(rc);
ASSERT(m_pDC != NULL);
//将所有内容拷贝到屏幕上去;
m_pDC->BitBlt(0,0,rc.Width(),rc.Height(),&m_ImageMemo,0,0,SRCCOPY);
其中操作2,3都在OnTimer里面,
这样子即使画很多内容,也不会产生刷屏的。
获取更多帮主请关注小程序