第一步:
打开VC++6.0,【文件】->【新建】,弹出下面窗口:选择【工程】【Win32 Application】,填上【工程名称】,选择【位置】,【确定】即可。
点【完成】,如下图:
点【确定】,如下图:
第二步:
【文件】,【新建】,【C/C++ Header File】,填好【名称】,【确定】,如下图:
在【game.h】头文件里写:
#include
如下图:
然后【文件】,【新建】,【资源脚本】(Resource Script),填上【文件名】,点【确定】。如下图:
第三步:
【project】->【setting】->【Microsoft Function Class】选择【Use MFC in a Static Library】(使用MFC作为静态库)。如下图:
第四步:
【View】->【ClassWizard】点【是】,【OK】,【OK】
第五步:
【Insert】->【New Class】,【类的类型】选【Generic Class】,填好【名称】,【Derived From】填【CWinApp】【确定】后再【确定】,如下图:
同理,【Insert】->【New Class】,【类的类型】选【MFC Class】,填好【name】,【Basic Class】选【CFrameWnd】,【确定】,如下图:
第六步:
在【Class View】下双击【GameApp】,在 Virtual ~GameApp();下一行写
BOOL InitInstance();
第七步:
双击【GameApp()】,填上头文件写上下面的代码:
#include “GameWnd.h”
GameApptheapp;
BOOLGameApp::InitInstance()
{
m_pMainWnd=new GameWnd;
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
returnTRUE;
}
双击【GameWnd()】,补充完整GameWnd::GameWnd(),并注释掉 #include “stdafx.h”
双击【GameWnd】,把GameWnd()改成public属性
切换到【GameApp】编译运行。
补充画直线和椭圆:
右击【GameWnd】,选择【Add Windows Message Handler】
双击【WM_PAINT】,【确定】
双击【GameWnd()】
写如下代码:
引用文章:
15.6链表实例2迷宫
(1).通过创建Win32程序进行第一个窗口菜单程序,在头文件中必须导入#include,这个是MFC类库的头文件,需要调用MFC类库中的窗口类来创建窗口,所以需要该文件。
(2).创建资源文件,资源文件用来保存声音、图片等外部资源,即使当前的程序中你用不着资源文件,你也要创建它。
步骤:创建Resource Script文件后,对其选择Resource Includes资源包含,这个选项用来输入资源文件引用的头文件名,由于我们没有资源,所以保持默认不变。
(3).在创建完资源文件后,类向导(ClassWizard)[在View下]就可以使用了,类向导的作用是建立文件用来存放类的信息,创建的文件是clw文件。
(4).由于我们这个程序使用了MFC的类和函数,所以我们要设置以下项目,让它们可以调用MFC函数库。
步骤:Project下的Settings,在General菜单下的设置Microsoft Foudation Classes。其中有两个选项,Use MFC in a Static Library(以静态链接的方式调用MFC),它的作用是你编译后的程序就直接包含了调用MFC的部分的库,文件可能会大些,但是可以直接移到其他机器上运行;还有一个是Use MFC in a Shared DLL,它的作用是你编译后的程序中不包含MFC库,所以文件会比较校,但是如果你的程序直接移动到一个没有安装过MFC的机器上时,可能会导致找不到MFC的DLL。此处我们要选择以静态链接的方式调用MFC。当创建完成之后,我们就创建了一个Windows应用程序,这个Windows应用程序可以以静态连接的方式包含MFC,也就是说,这个程序可以包含微软基础库中的内容,比如说函数或者类,这样我们这个程序就可以挪动到其他没有安装过MFC的机器上运行。
(5).MFC是微软提供的一套基础类库,它包装了windows系统提供的API,用于进行windows系统应用软件开发,可以使开发更简单,也能提高开发效率。MFC指的就是Microsift Foundation Classes。
(6).我们使用VC++为我们提供的创建类工具来继承MFC编写好的显示窗口的类。Insert下有个New Class,然后打开分别创建一个MFC类和一个普通类,前者的父类选择CFrameWnd,后者的父类选择CWinApp,将前MFC的子文件中的构造放开权限,变成公开的。然后编译修正头文件错误。
(7).由于GameApp代表我们当前的应用程序,因此它的生老病死代表着应用程序的生老病死。它要在窗口诞生之前诞生,在窗口灭亡之后灭亡。一句话,它的寿命就是应用程序的寿命。从专业角度上来说,基于MFC框架生成的应用程序必须有且仅有一个从CWinApp派生的类的对象,在创建窗口之前必须先构造该对象。因此,我们首先要在CWinApp的派生类中,也就是GameApp中定义一个对象,这个对象代表应用程序。方法在GameApp.cpp文件的构造上方定义GameApp myApp即可。
(8).定义初始化函数,在GameApp.h中声明,在构造函数前声明BOOL InitStance();然后在它对应的cpp文件,也就是实现文件中定义该函数。在GameApp的构造函数中初始化与在InitStance()方法中初始化的不同在于WinMain会调用InitInstance函数对应用程序进行初始化,而WinMain类似于控制台的main函数,它不用程序来编写,由类库提供,并在应用程序启动时调用。
(9).在InitInstance中创建窗口,编写代码,m_pMainWnd=new GameWnd;意思是:在堆中创建一个窗口类对象,这个GameWnd是一个窗口类,并用m_pMainWnd来指向它,m_pMainWnd是在CWinThread中定义的一个CWnd(窗口)类型的指针变量,它指向了应用程序的主框架窗口。由于CWinApp是CWinThread的子类,而我们定义的GameWnd类又是从CWinApp继承而来,因此GameWnd中可以调用它的祖父的指针变量m_pMainWnd。同时,由于这里要调用GameWnd类的构造函数,所以要在GameApp.cpp的开头添加GameWnd类的头文件GameWnd.h。最后为GameWnd.cpp添加GameWnd的构造函数,添加代码Create(NULL,"迷宫游戏");第一个参数是窗口类名,假如为NULL,那么采用窗口类默认提供的类名,第二个参数是窗口的标题。
(10).返回GameApp.cpp中,在刚定义的窗口指针下调用其ShowWindow方法,如m_pMainWnd->ShowWindow(m_nCmdShow);该段代码表示调用ShowWindow()函数将Create创建的窗口显示出来。在调用完Create函数之后窗口已经建立,但它是在内存中的,并不显示在显示器中,只有调用ShowWindow函数后才会显示出来,它的参数m_nCmdShow指定窗口如何显示,在第一次调用ShowWindow时,应该使用m_nCmdShow作为参数,在随后调用ShowWindow函数时候,必须给定一个值,比如说SW_SHOW(显示)、SW_HIDE(隐藏)。
(11).窗口显示以后,假如我们的窗体内容有改变,那么我们还需要更新窗口,使用m_pMainWnd调用其UpdateWindow()方法,当窗口有改变的时候,它才起作用。该函数不断发送重绘消息WM_PAINT来刷新目标窗体,使窗体产生不断更新的效果,它有一个参数,如果值为false,就不对窗口进行更新。最后在InitInstance()这个方法中返回true,表示创建完毕。此刻可以编译程序,窗体就会显示在屏幕上。
(12).假设我们要在窗口中显示一个图片,这个图片的文件名为down1.bmp,它是一个位图,要显示这个位图,我们需要与MFC的GDI类打交道。那么什么是GDI类,GDI是Graphic Device Interface的缩写,意思是“图形设备接口”。由于程序员无法直接操作显示卡,所以MFC提供了GDI类,用来做为程序员与显示卡沟通的桥梁,比如说程序员发出画图的命令,那么GDI便会将这个画图的命令翻译成显示卡能懂的语言,然后要求显示卡去做,这样程序员要做的就是如何与GDI建立良好的沟通关系。GDI包含许多绘图类,比如说处理位图的CBitmap类,处理画刷的CBrush类,处理字体的CFont类,处理调色板的CPalette类,处理画笔的CPen类以及处理图形设备接口区域的CRgn类。
由于我们要显示的是一张位图,所以我们只需用到处理位图的CBitmap类,其他类就可以暂时放到一边去。
(13).首先创建CBitmap对象。可以通过VC++左边窗口的Class窗口右键对应的窗口类GameWnd,Add Member Variable增加成员变量,变量名类型为CBitmap*,而变量名字为bitmap,最后访问权限设置为Public。在GameWnd类中的构造函数下,通过bitmap=new CBitmap;创建CBitmap对象。然后通过LoadImage()API函数进行读取图片。然后通过LoadImage方法进行对bitmap的赋值,bitmap->m_hObject=LoadImage(NULL,"down1.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);假设函数原型为:HANDLE LoadImage(HINSANCE hinst,LPCTSTR lpszName,UINT uType,int cxDesired,int CyDesired,UINT fuLoad);各个参数含义如下:
hinst:处理包含被装载图像模块的特例。若要装在OEM图像,则设此参数值为0。
IpszName:处理图像装载。如果参数hinst为non-NULL,而且参数fuLoad省略。
LRLOADROMFILE的值时,那么参数IpszName是一个指向保留在hinst模块中装载的图像资源名称,并以NULL为结束符的字符串。如果参数hinst为空,并且LR_LOADFROMFILE被指定,那么这个参数低位字一定是被装载的OEM图像标识的。OEM图像标识符是在WINUSER.h头文件中定义的,下面列举出前缀的含义:OBM_OEM:位图;OIC_OEM图标;OCR_OEM:光标。如果参数fuLoad包含LR_LOADFROMFILE值,那么参数IpszName是包含有图像的文件名。
uType:指定被装载图像类型。此参数可以为下列值,其含义如下:
IMAGE_BITMAP:装载位图;IMAGE_CURSOR:装载光标;IMAGE_ICON:装载图标。
cxDesired:指定图标或光标的宽度,以像素为单位。如果此参数为0并且参数fuLoad值为LR_DEFAULTSIZE,那么函数使用SM_CXICON或SM_CXCURSOR系统公制值设定宽度;如果此参数为0并且值LR_DEFAULTSIZE没有被使用,那么函数使用目前的资源宽度。
cyDesired:指定图标或光标的高度,以像素为单位。如果此参数为0并且参数fuLoad值为LR_DEFAULTSIZE,那么函数使用SM_CXICON或SM_CXCURSOR系统公制值设定宽度;如果此参数为0并且值LR_DEFAULTSIZE没有被使用,那么函数使用目前的资源高度。
fuLoad:根据下面复合值列表指定函数值,值含义如下:
LR_DEFAULTCOLOR:缺省标志,它不作任何事情,它的含义是“无LR_MONOCHROME”。
LR_CREATEDIBSECTION:当参数uType指定为IMAGE_BITMAP时,使得函数返回一个DIB部分位图,而不是一个兼容的位图。这个标志在装载一个位图,而不是映射它的颜色到显示设备时非常有用。
LR_DEFAULTSIZE:若cxDesired或cyDesired未被设为0,使用系统指定的公制值标识光标或图标的宽和高。如果这个参数不被设置且cxDesired或cyDesired被设为0,函数使用实际资源尺寸。如果资源包含多个图像,则使用第一个图像的大小。
LR_LOADFROMFILE:根据参数IpszName的值装载图像。若标记未被给定,IpszName的值为资源名称。
LW_LOADMAP3DCOLORS:查找图像的颜色表并且按下面相应的3D颜色表的灰度进行替换。
若fuLoad包括LR_LOADTRANSPARENT和LR_LOADMAP3DCOLORS两个值时,则LRLOADTRANSPARENT优先。但是,颜色表接口由COLOR_3DFACE替代,而不是COLOR_WINDOW。
LR_MONOCHROME:装载黑白图。
LR_SHARED:若图像将被多次装载则共享。如果LR_SHARED未被设置,则再向同一个资源第二次调用这个图像时就会再装载以便这个图像且返回不同的句柄。不要对不同标准尺寸的图像使用LR_SHARED,装载后可能会有改变,或是从文件中被装载。
(14).句柄是什么?句柄是一个指向指针的指针,我们知道,指针中保存的是内存地址,那么一个指向指针的指针,它保存的就是另一个指针的地址,我们可以通过一个指针来找到另一个指针,然后再通过另一个指针访问到具体的数据。
我们知道,当运行一个占用大量内存的程序时,系统内存很快就会被填满,这时Windows就会自动将那些暂时不用的数据放到硬盘中,而这些数据所占的空间就是虚拟内存。打个比方,电脑的剩余物理内存只有1G,我们同时运行游戏和QQ,游戏占用1G内存,而QQ占用100M,假如没有虚拟内存,那么QQ就不能运行,因为系统无法给QQ分配合适大小的内存,但是有了虚拟内存,那么就可以将游戏的一些不常用的数据转移出来,存放到虚拟内存中,比如说保存到硬盘上的一个叫pagefile.sys的文件中,同时释放掉这些被转移的数据,这样就有了足够的内存运行QQ,而当游戏运行到需要加载哪些被转移的数据时,可以释放掉一些不常用的数据,将其保存到硬盘文件pagefile.sys中,然后再读取pagefile.sys文件中关于游戏的数据,这样循环移动数据的过程就是微软的虚拟内存技术。
我们看到,为了最大限度的使用物理内存,Windows需要经常在武力内存和虚拟内存之间来回移动数据,以此来满足各种应用程序的内存需要。数据被移动意味着它的地址发生了变化。假如我们仍然按照先前的地址来访问它,是会出错的。为了解决这个问题,Windows操作系统专门腾出一块内存空间用来保存数据在内存中的地址变化,Windows操作系统每次移动数据后,都要把数据新的地址告知这个内存空间来保存。而记录地址变化的这块内存空间它的地址是保持不变的。我们把这个不变的地址叫做句柄,我们就可以通过该句柄找到数据的最新地址,然后访问该数据。但是,必须注意的是程序每次重新启动,Windows操作系统所分配的句柄都是不一样的,这就好像每次抽奖都抽到不同的号码一样,当然也有可能抽到同一个号码,不过几率很小。
(15).图片的显示其实是一个复制与粘贴的过程,打个比方:我们将一幅图片复制到WORD中去的时候,通常需要首先确定好操作的图片,然后选择复制,这时图片就自动加载到剪贴板中,通过运行Clipbrd可以看到剪贴板中文件的位置,这个剪贴板可看做是一块内存区域,它保存了复制好的图片,我们完成了加载图片到内存的操作后,接着我们打开WORD,这一步等于是将内存与WORD建立好联系,这样我们就不会粘贴到别的地方去,跟着我们将光标转移到需要粘贴的位置处,最后我们选择粘贴。那么图片就自动粘贴到了WORD中。因此我们要将图片在窗口中显示出来,一共分为四个步骤:第一,将位图复制到内存中;第二,获得作画的区域,即窗口;第三,将内存与窗口相关联;第四,将内存中图片粘贴到窗口中去,完成绘画。
(16).将位图复制到内存中的方法:首先需要在窗口类GameWnd的构造函数中建立一块内存,通过CDC *mdc = new CDC;用mdc指向这块内存,由于mdc这个指针在构造函数结束后还要使用,所以我们最好将指针定义为窗口类GameWnd的成员,然后去掉构造函数中的CDC *声明。
(17).然后我们来获得作画的区域,CClientDC dc(this);CClientDC代表客户区域,客户区域表示用户操作的区域,我们用客户区类声明了一个dc对象,然后将this传递进去,由于dc是在窗口类的构造函数中定义的,所以this指向的是当前窗口类的一个窗口对象。由于this指向的是当前的窗口对象,所以dc就代表这个窗口的客户区域。我们获得了作画的区域以后,接下来就要将内存与绘制图片的窗口相关联,也就是将内存mdc与窗口客户区域dc相关联,关联的方法使用mdc调用CreateCompatibleDC(),然后将窗口dc的地址传递进去,如:mdc->CreateCompatibleDC(&dc);这里调用了CDC类的CreateCompatibleDC(创建兼容DC)成员函数将窗口dc与内存mdc关联起来。这样就将内存与窗口建立了联系,注意这个CreateCompatibleDC函数它需要某个设备环境的内存地址,比如说窗口dc的内存地址,所以用取地址符取得了窗口dc的内存地址,DC是Device Context的缩写,即设备环境,设备环境好比是画家的画布,而图形(位图、画刷、画笔、调色板、字体等)则代表画家手中的画笔,选择不同的画笔在不同的画布上作画,则会勾勒出不同的画面。而CDC是设备环境类,集合了多种设备环境,比如说:代表操作窗口的CCllientDC,代表整个屏幕的CWindowDC,响应WM_PAINT消息的CPaintDC,以及响应Meta File的CMetaFileDC。
(18).将图片放到内存mdc中,mdc->SelectObject(bitmap);将mdc中的图片黏贴到窗口中去,dc.BitBlt(x,y,width,height,mdc,bx,by,SRCCOPY);x,y表示目的地的x,y坐标;idth,height表示目的地的宽度和高度,mdc表示内存的mdc;bx,by表示图片显示在窗体上是从什么位置开始;SRCCOPY表示模式,按原样复制,不拉伸。此时发现运行时什么都没有。现在对GameWnd增加Windows Message Handler,左边选择WM_PAINT,右边选择Add and Edit,将BitBlt方法放置到这个位置,再编译运行图像就显示出来了。
(19).什么时候可以调用重画呢?当窗体的大小改变或者最小化,窗体需要进行重画。这意味着旧的窗体区域被销毁,新的窗体区域被建立。WINDOWS会捕捉销毁的或者说是无效的窗体区域,并发送两个消息,WM_PAINT(通知客户区有变化)和WM_NCPAINT(通知非客户区有变化)。非客户区的重画系统自己搞定了,而客户区的重画需要我们自己来完成,它需要响应WM_PAINT消息的OnPaint()来重画窗口。在创建OnPaint()函数后会自动创建一行语句:CPaintDC dc(this);CPaintDC与CClientDC的区别在于:这个CPaintDC只能用来响应窗口重绘消息(WM_PAINT),CPaintDC是从CDC派生出来的,在构造时自动调用CWnd::BeginPaint开始绘图,在BeginPaint函数中获得WM_PAINT消息所给予的新的窗口区域的大小,并进行绘制,析构时调用CWnd::EndPaint结束绘图,EndPaint()除了清空窗口区域外,还负责从消息队列中清除WM_PAINT消息。这样窗体在重画一遍之后就不再重画了。因此,在处理窗口重画时,必须使用CPaintDC,否则WM_PAINT消息无法从消息队列中清除,将导致不断地窗口重画。CClientDC也是从CDC派生出来的,一般用于客户区窗口的绘制,构造时自动调用GetDC函数,析构时自动调用ReleaseDC函数,由于CClientDC不能调用EndPaint()从消息队列中清除WM_PAINT消息,所以将导致不断的窗口重画。总之,CClientDC不能像CPaintDC那样在dc销毁时调用EndPaint()从消息队列中清除WM_PAINT消息,所以WM_PAINT当dc销毁后会不断地新建dc,然后窗体的重画就不停地执行下去。
(20).BeginPaint()与EndPaint()的作用:BeginPaint函数的作用是告诉Windows系统,要开始向显示卡中输出图形了,由于Windows系统通常很忙,所以BeginPaint函数把本次请求放到消息队列里。让Windows系统忙完别的事情后来处理这个请求。
但是由于多数电脑的显示卡只有一个,这样要将图形显示完整必须独占显示卡。Windows操作系统很好的处理了这一点,它以线程的方式来处理每个显示请求,比如说:它让一个图形显示完毕后再来显示另一个,而不是一个图形显示一部分,另一个图形也显示一部分。
本章节所要显示的图形是窗口中的人物图片,这样BeginPaint函数就向Windows操作系统发送一个请求,大意是:窗口中的内容需要更新了,你安排好吧。同时它还提供了窗口的句柄以及窗口这个区域的大小。Windows操作系统接受到这个请求,就会为窗口这个区域分配一个句柄,这个句柄表示我们只能在这个窗口区域内绘图,其他区域都是无效的。当BeginPaint函数返回时,就得到了这个句柄,有了这个句柄,接下来的显示都将在这个窗口区域中进行,这个窗口就可以看做是一个画布,我们可以调用一大堆绘画函数在这个画布上涂抹。比如说我们调用BitBlt函数来显示一幅人物图片。当绘画完成后,我们必须调用EndPaint函数来释放掉BeginPaint独占的显示卡,因为不释放回去,别的程序永远无法使用被BeginPaint函数霸占的显示卡来显示图形,显示卡就被死锁了。
(21).为GameWnd增加一个成员二维数组变量,CBitmap* bitma[4][2]。在窗口的构造函数中如下定义将二维数组变量和图片对象对应起来。
Create(NULL,"迷宫游戏");
char ch[8];
for(int i=0;i<4;i++){
for(int j=0;j<2;j++){
sprintf(ch,"%d_%d.bmp",i+1,j+1);
bitma [i][j]=new CBitmap;
bitma [i][j]->m_hObject=LoadImage(NULL,ch,IMAGE_B
ITMAP,0,0,LR_LOADFROMFILE);
}
}
mdc = new CDC;
CClientDC dc(this);
mdc->CreateCompatibleDC(&dc);
mdc->SelectObject(bitma [0][0]);
然后为GameWnd窗口类增加Windows Message Handler,左边选择WM_CREATE,进行Add and Edit,增加SetTimer(时间器编号,时间间隔(毫秒),回调函数);此处我们如下操作:SetTimer(1,300,NULL)。在构造函数中我们通过Create函数,向编译器发送WM_Create消息,而响应该消息的方法是OnCreate函数,从而来创建窗口的属性,但不会产生窗口,在窗口显示前进行设置,计时器放在其中表示在窗口启动时进行定义。NULL表示不使用回调函数,通过系统自定义的OnTimer函数处理WM_Timer消息。在类中定义两个全局变量int dir;//方向变量,int index;//下标图片变量,在构造函数中进行赋值,index=0;dir=0;同样右键窗体类GameWnd中Add Window Message Handler,左边选择WM_TIMER,WM_CREATE,右边选择Add and Edit,在该函数中输入:
CClientDC dc(this);
if(dir>=4){
dir=0;
}
if(index<2){
mdc->SelectObject(bitma[dir][index]);
index++;
}else{
index=0;
dir++;
mdc->SelectObject(bitma[dir][index]);
}
dc.BitBlt(0,0,117,117,mdc,0,0,SRCCOPY);
CFrameWnd::OnTimer(nIDEvent);
(22).以同样方式添加按键事件,onKeyDown下所有代码如下:
void GameWnd::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: Add your message handler code here and/or call default
CClientDC dc(this);
dc.BitBlt(x,y,117,117,mdc,0,0,WHITENESS);
if(nChar==VK_DOWN){
y+=20;
if(dir==3){
index++;
if(index==2){
index=0;
}
}else{
index=0;
dir=3;
}
}
if(nChar==VK_LEFT){
x-=20;
if(dir==0){
index++;
if(index==2){
index=0;
}
}else{
index=0;
dir=0;
}
}
if(nChar==VK_UP){
y-=20;
if(dir==1){
index++;
if(index==2){
index=0;
}
}else{
index=0;
dir=1;
}
}
if(nChar==VK_RIGHT){
x+=20;
if(dir==2){
index++;
if(index==2){
index=0;
}
}else{
index=0;
dir=2;
}
}
mdc->SelectObject(bitma[dir][index]);
dc.BitBlt(x,y,117,117,mdc,0,0,SRCCOPY);
CFrameWnd::OnKeyDown(nChar, nRepCnt, nFlags);
}
其后将onPaint函数和计时器注释掉,编译即可运行。
(23).定义墙壁数组,并记录下入口处的位置:0表示可行走,1表示墙壁,2表示入口,3表示出口。
//定义墙壁数组
int wall[8][8]={
1,1,1,1,1,1,2,1,
3,0,0,1,0,0,0,1,
1,1,0,0,0,1,1,1,
1,0,0,1,0,0,0,1,
1,1,1,1,0,1,1,1,
1,0,0,0,0,0,0,1,
1,0,1,0,1,0,0,1,
1,1,1,1,1,1,1,1
};
//用来保存入口变量
int m,n;
在构造中增加:
for(int i=0;i<8;i++){
for(int j=0;j<8;j++){
if(wall[i][j]==2){
m=i;
n=j;
break;
}
}
}
wallp =new Bitmap;
wallp->m_hObject=LoadImage(NULL,"wall.bmp",IMAGE_BITMAP,93,100,LR_LOADFORMFILE);
增加成员方法:
Add Member function,类型void,名字为Start。
CClientDC dc(this);
mdc->SelectObject(wallp);
for(int i=0;i<8;i++){
for(int j=0;j<8;j++){
if(wall[i][j]==1){
dc.BitBlt(j*93,i*100,117,117,mdc,0,0,SRCCOPY);
}
}
}
mdc->SelectObject(bitma[0][0]);
dc.BitBlt(n*93,m*100,93,100,mdc,0,0,SRCCOPY);
start=false;
全局变量中定义:
//用来判断初始画面是否重画
BOOL start=true;
在计时器的OnTimer方法中定义:
if(start){
Start();
}
在OnPaint()方法中增加:CPaint dc(this);
最后在构造中重新定义窗口大小:
Create(NULL,"迷宫游戏",WS_OVERLAPPEDWINDOW,CRect(0,0,117+93*7,117+100*7));
【转载】