MFC-双缓冲技术

来源:互联网 发布:113什么意思 网络聊天 编辑:程序博客网 时间:2024/05/17 01:19

在做俄罗斯方块游戏的时候,遇到游戏过程中屏幕闪烁问题,解决办法如下:

使用双缓冲技术解决屏幕闪烁

  • 运行程序,会发现程序有些闪烁,这是因为程序受WM_TIMER 消息触发,调用OnTimer
    函数,OnTimer 函数中调用Invalidate 函数的结果。Invalidate 的调用会触发对OnDraw 函数
    的调用,从而不停地重绘窗口的结果。
  • 在VC++的文档、视图结构中,CView 的OnDraw 函数用于实现绝大部分图形绘制的工
    作。如果用户改变窗口尺寸,或者显示隐藏的区域,OnDraw 函数都将被调用来重画窗口。
    并且,当程序文档中的数据发生改变时,一般必须通过调用视图的Invalidate(或InvalidateRect)
    成员函数来通知Windows 所发生的改变,对Invalidate 的调用也会触发对OnDraw 函数的调
    用。正因为OnDraw 函数被频繁调用,所以在其执行时,每次都刷新填充一次视图客户区域,
    便会使屏幕不稳定,产生闪烁现象。
  • 这里介绍采用双缓冲方式消除屏幕闪烁的方法。普通绘图方式与双缓冲绘图方式的区别
    在于:普通绘图方式可以看做是在屏幕上直接绘制图形,双缓冲绘图方式是现在内存中创建
    的“虚拟屏幕”上绘制,然后将绘制完成的图形一次性“拷贝”到屏幕上。

修改视图类的OnDraw 函数:

void CMyTetrisView::OnDraw(CDC* pDC){    CMyTetrisDoc* pDoc = GetDocument();    ASSERT_VALID(pDoc);    int m_nWidth, m_nHeight;    CDC m_memDC;    CBitmap m_memBmp;    //1.用于映射屏幕的内存设备环境    //获取游戏窗口的大小用于下面设置内存位图的尺寸    CRect windowRect;    GetClientRect(&windowRect);    m_nWidth = windowRect.Width();    m_nHeight = windowRect.Height();    //内存设备环境与屏幕设备环境关联(兼容)    m_memDC.CreateCompatibleDC(pDC);    //内存位图与与屏幕关联(兼容),大小为游戏窗口的尺寸    m_memBmp.CreateCompatibleBitmap(pDC, m_nWidth, m_nHeight);    m_memDC.FillSolidRect(windowRect, RGB(0, 0, 0));    //内存设备环境与内存位图关联,以便通过m_memDC 在内存位图上作画    m_memDC.SelectObject(&m_memBmp);    DrawImage(bin, outputImage, &m_memDC, bin2, outputImage2, binN, outputImageN, binN2, outputImageN2);    //把内存DC 上的图形拷贝到电脑屏幕    pDC->BitBlt(0, 0, m_nWidth, m_nHeight, &m_memDC, 0, 0, SRCCOPY);    m_memDC.DeleteDC(); //删除DC    m_memBmp.DeleteObject(); //删除位图}

修改视图类的DrawImage 函数

// CMyTetrisView 消息处理程序void CMyTetrisView::DrawImage(CBin *bin, unsigned char** image, CDC *pDC, CBin *bin2, unsigned char** image2, CBin *binN, unsigned char** outputImageN, CBin *binN2, unsigned char** outputImageN2){    unsigned int width, i, j;    unsigned int height;    width = bin->getWidth();    height = bin->getHeight();    int nSize = 20;    CRect rect;    GetClientRect(&rect);    pDC->FillSolidRect(rect, RGB(137, 137, 137)); //绘制背景色    CRect rc;    CRect rc2;    CRect rcN;    CRect rcN2;    COLORREF BrickColor[8] = { 0xFFFFFF, 0xFF0000, 0x00FF00, 0x0000FF,        0x00FFFF, 0xFFFF00, 0x800000, 0x800080 };    for (i = 0; i<height; i++)    {        for (j = 0; j<width; j++)        {            rc = CRect(j*nSize, i*nSize, (j + 1)*nSize, (i + 1)*nSize);            rc2 = CRect((j + 24)*nSize, i*nSize, (j + 25)*nSize, (i + 1)*nSize);            //绘制面板            if (image[i][j] != 0)            {                pDC->FillRect(rc, &CBrush(BrickColor[image[i][j]]));                pDC->Draw3dRect(rc, GetLightColor(BrickColor[image[i][j]]),                    GetDarkColor(BrickColor[image[i][j]]));            }            if (image2[i][j] != 0)            {                pDC->FillRect(rc2, &CBrush(BrickColor[image2[i][j]]));                pDC->Draw3dRect(rc2, GetLightColor(BrickColor[image2[i][j]]),                    GetDarkColor(BrickColor[image2[i][j]]));            }        }    }    for (i = 0; i<4; i++)    {        for (j = 0; j<8; j++)        {            rcN = CRect((j + 11)*nSize, (i + 5)*nSize, (j + 12)*nSize, (i + 6)*nSize);            rcN2 = CRect((j + 37)*nSize, (i + 5)*nSize, (j + 38)*nSize, (i + 6)*nSize);            if (outputImageN[i][j] != 0)            {                pDC->FillRect(rcN, &CBrush(BrickColor[outputImageN[i][j]]));                pDC->Draw3dRect(rcN, GetLightColor(BrickColor[outputImageN[i][j]]),                     GetDarkColor(BrickColor[outputImageN[i][j]]));            }            if (outputImageN2[i][j] != 0)            {                pDC->FillRect(rcN2, &CBrush(BrickColor[outputImageN2[i][j]]));                pDC->Draw3dRect(rcN2, GetLightColor(BrickColor[outputImageN2[i][j]]),                    GetDarkColor(BrickColor[outputImageN2[i][j]]));            }        }    }}
1 0
原创粉丝点击