MFC飞机大战开发之绘制图像

来源:互联网 发布:java的设计模式有哪些 编辑:程序博客网 时间:2024/05/22 03:17

这一节来演示一种绘图的方法,让我们的程序真正的看得见~ 哈哈哈,而不再是命令行的黑框框。 采用的是二重缓冲的方式

先说一下当前工程的启动过程,省略一部分,直接看到我们的ChildView.cpp这个文件,里边有两个函数BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs)void CChildView::OnPaint() ,可以简单的理解为,前者是窗口出现之间,程序所做的事情,所以你可以把游戏的一些初始化的操作放在这个函数里边,后者就是绘制这个窗口,每执行一次这个函数,就会重新绘制一下当前的窗口,你所看到的动画啊,游戏啊 都是通过一直执行这个函数实现的动画的效果的~,好啦~ 说了这么一堆话了,来开始贴上我们的飞机们把~

第一步:

找到ChildView.h 这个头文件,在里边添加一些我们所需要的属性,

// 特性public:    //绘图相关    CRect m_client;//记录客户区大小    CDC m_cacheDC;   //缓冲DC      CBitmap m_cacheCBitmap;//缓冲位图

然后转到ChildView.cpp这个文件,修改OnPaint函数

void CChildView::OnPaint() {    CPaintDC dc(this); // 用于绘制的设备上下文    // TODO: 在此处添加消息处理程序代码    // 不要为绘制消息而调用 CWnd::OnPaint()    //获取窗口DC指针      CDC *cDC = this->GetDC();    //获取窗口大小      GetClientRect(&m_client);    //创建缓冲DC      m_cacheDC.CreateCompatibleDC(NULL);    m_cacheCBitmap.CreateCompatibleBitmap(cDC, m_client.Width(), m_client.Height());    m_cacheDC.SelectObject(&m_cacheCBitmap);    //————————————————————开始绘制——————————————————————      //把要绘制的内容都贴到m_cacheDC当中就可以了    Manager.Draw(&m_cacheDC);    //最后将缓冲DC内容输出到窗口DC中      cDC->BitBlt(0, 0, m_client.Width(), m_client.Height(), &m_cacheDC, 0, 0, SRCCOPY);    //————————————————————绘制结束—————————————————————      //在绘制完图后,使窗口区有效      ValidateRect(&m_client);    //释放缓冲DC      m_cacheDC.DeleteDC();    //释放对象      m_cacheCBitmap.DeleteObject();    //释放窗口DC      ReleaseDC(cDC);    ReleaseDC(cDC);}

我这段代码当中的Manager.Draw(&m_cacheDC); 就是把所有的内容都贴到缓冲DC当中(m_cachaeDC),Manager是一个类的实例对象,该类可以存储多个物体(比如:飞机,敌机,导弹等等),可以通过该类的Draw方法一次绘制所有的内容。 看到这里你可能说 哎呀 我不知道怎么写Manager这个类呀,我还是不知道怎么贴图啊,别着急~ 接下来我就给你们演示如何贴图~

我们试着新建一个类,就叫他Plane 类吧, 一个飞机有什么属性呢,嗯~ 有他的外观(贴图),长,宽,在游戏世界中还有一个属性是坐标,好,我们的类就长这个样子:

#pragma once#include <atltypes.h>#include <atlimage.h>class Plane{private:    CImage Image_;   //物体的贴图    int Height_;     //物体的高度    int Width_;      //物体的宽度    CPoint Postion_; //物体的位置坐标public:    Plane(){};    ~Plane(){};};

CImage Image_ ; 就是储存物体的模样(外观)的,我们把一张图片放进去就好了~ 来看看怎么放一张图片呢

一般来讲是通过 CImage的load方法加载图片的,比如Image_.Load("Plane.png"); ,然而我们想要最后生成的exe文件可以独立的运行就需要把图片加载到我们的资源当中,那么如何从我们的资源文件中加载图片呢,是通过这样的一个函数做到的

//从资源加载图片 第一个是资源的名称,第二个是资源的类型    BOOL LoadImageFromResource(UINT nResID, LPCTSTR lpTyp)    {        /*Image_.Destroy();*/        // 查找资源        HRSRC hRsrc = ::FindResource(AfxGetResourceHandle(), MAKEINTRESOURCE(nResID), lpTyp);        if (hRsrc == NULL) return false;        // 加载资源        HGLOBAL hImgData = ::LoadResource(AfxGetResourceHandle(), hRsrc);        if (hImgData == NULL)        {            ::FreeResource(hImgData);            return false;        }        // 锁定内存中的指定资源        LPVOID lpVoid = ::LockResource(hImgData);        LPSTREAM pStream = NULL;        DWORD dwSize = ::SizeofResource(AfxGetResourceHandle(), hRsrc);        HGLOBAL hNew = ::GlobalAlloc(GHND, dwSize);        LPBYTE lpByte = (LPBYTE)::GlobalLock(hNew);        ::memcpy(lpByte, lpVoid, dwSize);        // 解除内存中的指定资源        ::GlobalUnlock(hNew);        // 从指定内存创建流对象        HRESULT ht = ::CreateStreamOnHGlobal(hNew, TRUE, &pStream);        if (ht != S_OK)        {            GlobalFree(hNew);        }        else        {            // 加载图片            Image_.Load(pStream);            GlobalFree(hNew);        }        // 释放资源        ::FreeResource(hImgData);        return true;    }

如果是PNG图片的话,在通过这个函数把图片转为透明的(原本透明的部分)

//转换PNG图片为透明    static void TransparentPNG(CImage *png)    {        if (png->GetBPP() == 32)        {            for (int i = 0; i < png->GetWidth(); i++)            {                for (int j = 0; j < png->GetHeight(); j++)                {                    unsigned char* pucColor = reinterpret_cast<unsigned char*>(png->GetPixelAddress(i, j));                    pucColor[0] = pucColor[0] * pucColor[3] / 255;                    pucColor[1] = pucColor[1] * pucColor[3] / 255;                    pucColor[2] = pucColor[2] * pucColor[3] / 255;                }            }        }    }

最后 我们封装一个接口方便使用

    //从资源中加载图片    void LoadImage(UINT nResID, LPCTSTR lpTyp = _T("PNG"))    {        LoadImageFromResource(nResID, lpTyp);        if (lpTyp == _T("PNG"))            TransparentPNG(&Image_);    }    //对象的绘制方法    void Draw(CDC *cDC)    {        Image_.Draw(*cDC, Postion_.x, Postion_.y, Width_, Height_);    }

好啦,现在生成一个实例对象去试试吧~

    //————————————————————开始绘制——————————————————————      //把要绘制的内容都贴到m_cacheDC当中就可以了    plane.Draw(&m_cacheDC);    //plane是Plane类的实例对象,记得先给他加载一张图片哦~    //最后将缓冲DC内容输出到窗口DC中      cDC->BitBlt(0, 0, m_client.Width(), m_client.Height(), &m_cacheDC, 0, 0, SRCCOPY);

完成后运行一下看看吧,是不是小飞机出现在屏幕当中了呢

最后附上一个完整的飞机类

#pragma once#include <atlimage.h>#include <afxwin.h>class Plane{private:    CImage Image_;   //物体的贴图    int Height_;     //物体的高度    int Width_;      //物体的宽度    CPoint Postion_; //物体的位置坐标public:    Plane()    {        LoadImage(IMG_Plane); // 让对象初始化的时候自动加载图片        Height_ = 30;        Width_ = 30;        Postion_ = CPoint(Game_Width / 2, Game_Height);    };    ~Plane(){};    //转换PNG图片为透明    static void TransparentPNG(CImage *png)    {        if (png->GetBPP() == 32)        {            for (int i = 0; i < png->GetWidth(); i++)            {                for (int j = 0; j < png->GetHeight(); j++)                {                    unsigned char* pucColor = reinterpret_cast<unsigned char*>(png->GetPixelAddress(i, j));                    pucColor[0] = pucColor[0] * pucColor[3] / 255;                    pucColor[1] = pucColor[1] * pucColor[3] / 255;                    pucColor[2] = pucColor[2] * pucColor[3] / 255;                }            }        }    }    //从资源加载图片 第一个是资源的名称,第二个是资源的类型    BOOL LoadImageFromResource(UINT nResID, LPCTSTR lpTyp)    {        /*Image_.Destroy();*/        // 查找资源        HRSRC hRsrc = ::FindResource(AfxGetResourceHandle(), MAKEINTRESOURCE(nResID), lpTyp);        if (hRsrc == NULL) return false;        // 加载资源        HGLOBAL hImgData = ::LoadResource(AfxGetResourceHandle(), hRsrc);        if (hImgData == NULL)        {            ::FreeResource(hImgData);            return false;        }        // 锁定内存中的指定资源        LPVOID lpVoid = ::LockResource(hImgData);        LPSTREAM pStream = NULL;        DWORD dwSize = ::SizeofResource(AfxGetResourceHandle(), hRsrc);        HGLOBAL hNew = ::GlobalAlloc(GHND, dwSize);        LPBYTE lpByte = (LPBYTE)::GlobalLock(hNew);        ::memcpy(lpByte, lpVoid, dwSize);        // 解除内存中的指定资源        ::GlobalUnlock(hNew);        // 从指定内存创建流对象        HRESULT ht = ::CreateStreamOnHGlobal(hNew, TRUE, &pStream);        if (ht != S_OK)        {            GlobalFree(hNew);        }        else        {            // 加载图片            Image_.Load(pStream);            GlobalFree(hNew);        }        // 释放资源        ::FreeResource(hImgData);        return true;    }    //从资源中加载图片    void LoadImage(UINT nResID, LPCTSTR lpTyp = _T("PNG"))    {        LoadImageFromResource(nResID, lpTyp);        if (lpTyp == _T("PNG"))            TransparentPNG(&Image_);    }    //对象的绘制方法    void Draw(CDC *cDC)    {        Image_.Draw(*cDC, Postion_.x, Postion_.y, Width_, Height_);    }};
2 0
原创粉丝点击