版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
PAGEword文档可自由复制编辑word文档可自由复制编辑1.引言1.1游戏介绍连连看来源于街机游戏《四川麻将》和《中国龙》,是给一堆图案中的相同图案进行配对的简单游戏,在2003年,一个叫做朱俊的网友将这种形式搬到了PC上,立刻成为办公一族的新宠,并迅速传遍了世界各地。饱受工作压力的人们没有太多的时间进行复杂的游戏,而对于这种动动鼠标就能过关的游戏情有独钟。之后村子的连连看风靡版,阿达的连连看奥运版,连连看反恐版,还有敏敏连连看,水晶连连看等遍地开花,造就了一个连连看的新世界。连连看游戏有多种地图样式和道具系统、大大加强了游戏的可玩性,是一款老少皆宜的休闲佳品。1.2目的网络小游戏制作的目的是满足了人们休闲的需要,在紧张工作之余休闲类的小游戏能够给人带来最大程度的放松,也可以增进人们之间的交流,沟通,通过游戏还可以认识更多的朋友,也可以到达跨省、跨市,甚至跨国间人们互相娱乐的目的。另外也通过本程序将三年来所学的专业知识和其他方面的知识融入到实际应用中。1.3主要问题开始制作游戏时,主要要解决的问题有以下几个方面:如何设置整个游戏的界面;如何控制连连看游戏中随机图片的生成且每种图片必须为偶数个;游戏开始后,判断鼠标两次点击的图片能否消去,即图片是否相同且图片之间路径的判断.1.4开发环境 Intel®Pentium®42.0GHz,512M内存,80G硬盘 Microsoft®Windows™2000Professional Microsoft®VisualC++6.02.需求分析关于连连看的功能描述如下:运行游戏并进行初始化工作,将整个游戏区域分成纵向和横向扩展的若干个小方块,并且这些小方块是由多种动物图案成对地分布于游戏区域的不同位置。玩家可以通过选取相同的两个物件来对它们进行消除的操作,直到将游戏区域中的所有方块对都被消除后为胜利。游戏的整体运行效果如图1.1。图1.13.功能模块的设计3.功能模块的设计3.1类设计这个游戏的主要类是游戏模式类,类名为CMyDlg。这个类主要对包括图案方块的销毁判断,游戏胜利判断以及整个游戏用户交换功能的实现。它uml图如下:CMyDlgm_mem3DBkDC:CDCm_mem3DBkBmp:CBitmapm_memAnimalDC:CDC m_memAnimalBmp:CBitmapm_MemDC:CDC m_memBitmap:CBitmapm_map:intm_nRow: int m_nCol:int m_nX1:int m_nY1:int GameDraw(CDC*pDC):voidStartNewGame():voidPreTranslateMessage(MSG*pMsg):BOOLIsLink(intx1,inty1,intx2,inty2):BOOLIsWin(void):BOOLX1_Link_X2(intx,inty1,inty2):BOOLY1_Link_Y2(intx1,intx2,inty):BOOLOneCornerLink(intx1,inty1,intx2,inty2):BOOLTwoCornerLink(intx1,inty1,intx2,inty2):BOOLYThrough(intx,inty,BOOLbAdd):BOOLXThrough(intx,inty,BOOLbAdd):BOOLLineX(intx,inty1,inty2):BOOLLineY(intx1,intx2,inty):BOOL这些成员函数和成员变量的算法分析与设计以及核心算法中有详细介绍。3.2.框架的搭建从图1.1可以看出,整个运行的界面由菜单栏和游戏区域的图形显示组成,因此,需要用对话框模板的方式去搭建整个框架再添加一个菜单栏。首先,创建一个基于对话框模板的项目,如图1.2所示。图1.2在创建过程的第一步“MFC应用程序向导—步骤1”中应该选择“基本对话框”选项,确保应用程序的创建是对话框模板,如图1.3所示。图1.3然后添加菜单栏为对话框增加菜单栏并为对话框创建一个菜单资源IDR_MENU1。图1.4在对话框的属性对话框中在Menu属性中选择刚创建的菜单资源IDR_MENU1。此时保存编译后,在对话框中就可看到菜单。图1.5点击快捷键Ctrl+W,在“AddaClass”对话框中选择已存在的对话框类“Selectanexistingclass”,打开“SelectClass”对话框。图1.6选择对话框类,本例中的类名为CMyDlg,选中进入下一步。图1.7进入MFCClassWizard对话框,在消息映射属性页中,为菜单增加消息处理函数,为子菜单增加COMMAND处理函数函数名为默认函数名。如图1.8所示:图1.8给各个子菜单添加消息映射,同上所述。然后编辑函数代码,实现自己定义的功能,添加的代码如下:voidCMyDlg::Onexit(){ //TODO:AddyourcommandhandlercodehereCDialog::OnCancel(); }voidCMyDlg::Onnewgame(){ //TODO:AddyourcommandhandlercodehereStartNewGame(); }voidCMyDlg::Onathour(){ //TODO:AddyourcommandhandlercodehereMessageBox("11物41陈晓丽"); } voidCMyDlg::Onabout(){ //TODO:AddyourcommandhandlercodehereMessageBox("本游戏连连由C++MFC设计实现,是给一堆图案中的相同图案进行配对的简单游戏"); }编译运行后,点击各子菜单,将弹出对话框。4.算法分析与设计在对算法进行分析前,应先抽象出游戏的基本是具结构,而对连连看游戏来说,核心的部分应该是整个游戏区域的地图数据。那么,下面将分析游戏特性,然后设计出标识地图的数据结构。4.1游戏地图数据设计对于整个游戏区域,可以把它看作一个是由若干个小方块构成的地图,而且每一个小方块放置着不同的动物图案,可将其称之为图案小方块。这些图案小方块零散地分布在地图的不同位置区域,并且每一个图案小方块都有与其对应的完全一样的另外一个小方块,如图1.8所示。图1.9如图1.9所示,整个游戏游戏区域被抽象成一个有坐标位置属性的平面,平面上零散地分布着若干个小方块,并且这些小方块的物种起码是成对出现的。经过前面的描述和分析后,可以把游戏区域地图用一个数组m_map来表示。m_map是把地图设计成一个动态分配的int整形一维数组,对地图中的行列数的表达,用一个转换法则即可。可以在CMyDlg类对象定义中添加地图核心数据的成员变量,具体如下://地图位置相关属性组 int*m_map;//动态地图数据头指针(一维数组) int m_nRow; //地图的行数(虚拟) int m_nCol; //地图的列数(虚拟)上面的成员变量中定义了一个整形指针标量m_map,用于记录动态分配出来的一维数组地图空间的首地址。对于地图区域中的某个小方块的类型,可以用一个整形的ID来进行识别。这里为标识地图的行列位置分别添加m_nRow和m_nCol变量。现在,地图的数据结构已经设计好。下面对游戏进行初始化。由于方块需要成对地出现,因此在做地图的初始化时,不仅仅是对动物种类做简单的随机取数,然后将该随机选取出来的物件放到地图区域中去就了事,而是需要成对地对物种进行成对选取,就是说地图中的小方块必须是偶数个。前面提到过,把地图数组设置成动态分配方式,目的是让其数据空间可以根据行列数的需求动态地获取,而对于实际不同大小比例的地图可以预先定义几组关于行列数的宏来实现。当需要创建时,根据宏值的不同分配不同大小的地图空间即可。接下来在CMyDlg类的构造函数对地图数据进行相关的初始化:#defineROWCOUNT7 //行数#defineCOLCOUNT12 //列数CMyDlg::CMyDlg(CWnd*pParent/*=NULL*/) :CDialog(CMyDlg::IDD,pParent){ …… //记录方块置为无效状态 m_nY1=BLANK_STATE; m_nX1=BLANK_STATE; //初始化行列数 m_nRow=ROWCOUNT; m_nCol=COLCOUNT; //根据行列数动态分配内核数据数组空间 m_map=newint[m_nRow*m_nCol];}CMyDlg::~CMyDlg(){ //释放动态数组空间 delete[]m_map;}在CMyDlg类对象的实现中,定义了一些关于地图行列数的宏,如ROWCOUNT和COLCOUNT,并且在CMyDlg类对象的构造函数中,进行了行列的真实确认赋值,并根据当前行列数的大小对地图数据空间进行动态创建。因为地图数据是用new在堆栈动态创建的,所以在销毁该对象时要将这些内存空间释放,如代码所示在CMyDlg类对象的析构函数中调用delete将m_map指向的所有空间都释放掉。4.2数据的初始化工作接下来,再分配好的空间中放上适当的图案方块物件,对数据进行初始化。即需要对地图空间内的数据进行成对性的随机布局,因此可以将该功能的实现封装在StartNewGame()函数里面,其代码如下:voidCMyDlg::StartNewGame(){ //初始化地图,将地图中所有方块区域位置置为空方块状态 for(intiNum=0;iNum<(m_nCol*m_nRow);iNum++) { m_map[iNum]=BLANK_STATE; } //部下随机种子 srand(time(NULL)); //生成随机地图 //将所有匹配成对的动物物种放进一个临时的地图中 CDWordArraytmpMap; for(inti=0;i<(m_nCol*m_nRow)/6;i++) for(intj=0;j<6;j++) tmpMap.Add(i); //每次从上面的临时地图中取走(获取后并在临时地图删除) //一个动物放到地图的空方块上 for(i=0;i<m_nRow*m_nCol;i++) { //随机挑选一个位置 intnIndex=(int(rand()*0.1+rand()*0.01+rand()))%tmpMap.GetSize(); //获取该选定物件放到地图的空方块 m_map[i]=tmpMap.GetAt(nIndex); //在临时地图除去该动物 tmpMap.RemoveAt(nIndex); } //更新显示 Invalidate(TRUE);}在游戏进行初始化的过程中,应该先对整个地图中的各个区域做必要的初始化操作,将它们的状态设置为BLANK_START空白方块状态(无动物图案方块),关于BLANK_START空白方块状态的定义,跟其他动物方块的物种定义表达类似,也是用整数ID来对它进行标识,不过不同的是,由于他代表该方块区域无图案,所以这里用-1的宏值来表示,具体定义如下:#defineBLANK_STATE-1//空方块(没有任何动物)可以看到,对图案方块的布局,先用srand()函数对时间函数布下随机种子,然后调用rand()函数对具体的图案方块的种类进行随机的获取。在这里需要引入一个临时地图tmpMap,该临时地图的大小与内核数据地图的大小一致,并且先添置好4组完全一样的图案类型ID数据(0~(m_nCol*m_nRow)/4),然后再将已经安放在tmpMap中的图案作随机抽取,并放到内核地图数据中去,将取出的元素从tmpMap中除去。4.3快捷方式的创建按Ctrl+W为类添加消息映射PreTranslateMessage,双击函数名为该函数添加如下代码BOOLCMyDlg::PreTranslateMessage(MSG*pMsg){ //TODO:Addyourspecializedcodehereand/orcallthebaseclass if(pMsg->message==WM_KEYDOWN) { if(pMsg->wParam==VK_F2) { StartNewGame(); }if(pMsg->wParam==VK_F3) {CDialog::OnCancel(); } }在运行游戏时按下F2便可重新开始新游戏,按F3便可退出游戏。5.核心算法在完成地图数据设计后,就开始展开游戏核心的设计,该部分主要包括图案方块的销毁判断,游戏胜利判断以及整个游戏用户交换功能的实现。5.1图案方块的连接判断对于选中的两个方块的销毁,他们必须符合下面3个条件:(1)选中的两个方块图案相同。(2)选中的两个方块之间没有障碍物阻碍的情况下,可以用若干个垂直的直线线段连接起来。(3)这些将它们连接起来的直线线段的折点不超过两个(连接线由x轴和y轴的平行线组成)。现在针对(2)和(3)进行分析,同种物件的连接方式大致可以分成以下3种:直接方式有一个折点的垂直线段连接。有两个折点的垂直线段连接.。1.直接连接方式在直接连接方式中,必须要求所选定的两个方块在同一水平直线上(可以为x方向或y方向),并且两个方块之间没有任何其他图案方块。2.一个这点连接方式所选定的两个方块如果通过折点的方式连接,那么对于折点来说,每个折点必定有且至少有一个坐标(x或y)是和其中一个目标点相同的,即折点必定在两个目标点所在的x方向或y方向的直线上。此外,对于一个折点连接的情况,折点应该为第一个选中方块的横向线或纵向线与第二个选中方块的纵向线和横向线相交而得出。3.两个折点的连接方式这种方式的两个折点所连成的直线与两物件的直接连线可以构成平行线,因此可以根据这个规律,将这条水平线在游戏区域允许的条件上下移动,然后通过判断整条带垂直折线点的曲线之间有无障碍物方式来确定是否可以连同。这种情况可以分为两种情况:(1)选中的两图案方块在同一直线,两折点间的直连线可在其这两个方块之间的空间位置作移动,其约束是不超过游戏边界区域。(2)选中的两图案方块不在同一直线,两折点间的直连线可在两个方块之间的空间位置作移动,其约束是两方块之间的区域。经过上面详细的分析后,可以对选定的两方块是否可以作抵消操作可以这样设计下去。首先,对简单的直接连情况进行判断,看其是否符合条件,假如不能,再加深一个级别的复杂度,对一个折点的情况进行判断,依次类推,如下图所示。图1.10图1.11根据如图1.6所示的流程图,可以对选定的两个方块(分别在(x1,y1)以及(x2,y2)两个区域位置,其中x,y分别代表行与列的概念)是否可以抵消作以下实现。把该功能封装在IsLink()函数里面,其代码如下所示://判断选中的两个方块是否可以消除BOOLCMyDlg::IsLink(intx1,inty1,intx2,inty2){ //X直连方式 if(x1==x2) { if(X1_Link_X2(x1,y1,y2)) returnTRUE; } //Y直连方式 elseif(y1==y2) { if(Y1_Link_Y2(x1,x2,y1)) returnTRUE; } //一个转弯直角的联通方式 if(OneCornerLink(x1,y1,x2,y2)) { returnTRUE; } //两个转弯直角的联通方式 elseif(TwoCornerLink(x1,y1,x2,y2)) { returnTRUE; } returnFALSE;}在上面的实现中,先是对直连方式中的x方向直连Y1_Link_Y2()以及y方向直连X1_Link_X2()这两种情况进行判断,如果尚未取得结果,再通过调用OneCornerLink()函数对一个折点的情况进行判断,或者更糟糕的时候调用TwoCornerLink()函数对两个这点的情况进行判断,然后得出最终结果。下面将对上面涉及到的子功能模块进行实现,代码如下所示://X直接连通BOOLCMyDlg::X1_Link_X2(intx,inty1,inty2){ //保证y1的值小于y2 if(y1>y2) { //数据交换 intn=y1; y1=y2; y2=n; } //直通 for(inti=y1+1;i<=y2;i++) { if(i==y2) returnTRUE; if(m_map[i*m_nCol+x]!=BLANK_STATE) break; } //左通 if(XThrough(x-1,y1,FALSE)&&XThrough(x-1,y2,FALSE)) returnTRUE; //右通 if(XThrough(x+1,y1,TRUE)&&XThrough(x+1,y2,TRUE)) returnTRUE; returnFALSE;}//Y直接连通BOOLCMyDlg::Y1_Link_Y2(intx1,intx2,inty){ if(x1>x2) { intx=x1; x1=x2; x2=x; } //直通 for(inti=x1+1;i<=x2;i++) { if(i==x2) returnTRUE; if(m_map[y*m_nCol+i]!=BLANK_STATE) break; } //上通 if(YThrough(x1,y-1,FALSE)&&YThrough(x2,y-1,FALSE)) returnTRUE; //下通 if(YThrough(x1,y+1,TRUE)&&YThrough(x2,y+1,TRUE)) returnTRUE; returnFALSE;}//是否同一直线通//BOOLCMyDlg::LineX(intx,inty1,inty2){ if(y1>y2) { inty=y1; y1=y2; y2=y; } for(inty=y1;y<=y2;y++) { if(m_map[y*m_nCol+x]!=BLANK_STATE) returnFALSE; if(y==y2) returnTRUE; } returnFALSE;}////是否同一直线通//BOOLCMyDlg::LineY(intx1,intx2,inty){ if(x1>x2) { intx=x1; x1=x2; x2=x; } for(intx=x1;x<=x2;x++) { if(m_map[y*m_nCol+x]!=BLANK_STATE) returnFALSE; if(x==x2) returnTRUE; } returnFALSE;}//1直角接口连通BOOLCMyDlg::OneCornerLink(intx1,inty1,intx2,inty2){ if(x1>x2) { intn=x1; x1=x2; x2=n; n=y1; y1=y2; y2=n; } if(y2<y1) { if(LineY(x1+1,x2,y1)&&LineX(x2,y1,y2+1)) returnTRUE; if(LineY(x2-1,x1,y2)&&LineX(x1,y2,y1-1)) returnTRUE; returnFALSE; } else { if(LineY(x1+1,x2,y1)&&LineX(x2,y1,y2-1)) returnTRUE; if(LineY(x2-1,x1,y2)&&LineX(x1,y2,y1+1)) returnTRUE; returnFALSE; } returnFALSE;}//2直角接口连通BOOLCMyDlg::TwoCornerLink(intx1,inty1,intx2,inty2){ if(x1>x2) { intn=x1; x1=x2; x2=n; n=y1; y1=y2; y2=n; } //右通 if(XThrough(x1+1,y1,TRUE)&&XThrough(x2+1,y2,TRUE)) returnTRUE; //左通 if(XThrough(x1-1,y1,FALSE)&&XThrough(x2-1,y2,FALSE)) returnTRUE; //上通 if(YThrough(x1,y1-1,FALSE)&&YThrough(x2,y2-1,FALSE)) returnTRUE; //下通 if(YThrough(x1,y1+1,TRUE)&&YThrough(x2,y2+1,TRUE)) returnTRUE; //右 for(intx=x1+1;x<m_nCol;x++) { if(m_map[y1*m_nCol+x]>-1) break; if(OneCornerLink(x,y1,x2,y2)) returnTRUE; } //左 for(x=x1-1;x>-1;x--) { if(m_map[y1*m_nCol+x]!=BLANK_STATE) break; if(OneCornerLink(x,y1,x2,y2)) returnTRUE; } //上 for(inty=y1-1;y>-1;y--) { if(m_map[y*m_nCol+x1]!=BLANK_STATE) break; if(OneCornerLink(x1,y,x2,y2)) returnTRUE; } //下 for(y=y1+1;y<m_nRow;y++) { if(m_map[y*m_nCol+x1]!=BLANK_STATE) break; if(OneCornerLink(x1,y,x2,y2)) returnTRUE; } returnFALSE;}BOOLCMyDlg::XThrough(intx,inty,BOOLbAdd){ if(bAdd) { for(inti=x;i<m_nCol;i++) if(m_map[y*m_nCol+i]!=BLANK_STATE) returnFALSE; } else { for(inti=0;i<=x;i++) if(m_map[y*m_nCol+i]!=BLANK_STATE) returnFALSE; } returnTRUE;}BOOLCMyDlg::YThrough(intx,inty,BOOLbAdd){ if(bAdd) { for(inti=y;i<m_nRow;i++) if(m_map[i*m_nCol+x]!=BLANK_STATE) returnFALSE; } else { for(inti=0;i<=y;i++) if(m_map[i*m_nCol+x]!=BLANK_STATE) returnFALSE; } returnTRUE;}这里把直接连接方式分为直通,左通,右通3种情况,如1.12图所示。下面简单介绍直通和左通两种情况(右通与左通类似)(1)直通:直通就是在选定的两个方块直连线中,没有被任何方块所阻碍。(2)左通:左通就是选定的两个方块的直连线之间有其他方块阻碍,但是通过它的左侧可以将它们无阻碍地连通。直连方式中的此种情况跟前面分析的两个折点连接方式中的其中一点相当类似,如1.13图所示。它们之间的区别就是,左通的连接线直接在其相邻的位置连通,从而不构成垂直折点的效果,而两个折点连同方式中的其中一个类似的情况是,线的连通起码要偏移一个方块的距离来形成连通。图1.12图1.13同理,有上通和下通,它们的情况与左通和右通类似。5.2游戏胜利的判断要判断游戏的胜利,实现起来比较简单,只需对地图中的所有区域的状态进行检测就可里了,只要检测到地图中有一个图案方块还没有被抵消,则证明游戏没有结束,完成判断。其代码如下所示://检测是否已经赢得了游戏BOOLCMyDlg::IsWin(void){ //检测所有是否尚有非未被消除的方块 //(非BLANK_STATE状态) for(inti=0;i<m_nRow*m_nCol;i++) { if(m_map[i]!=BLANK_STATE) { returnFALSE; } } returnTRUE;}游戏胜利界面如图1.14所示图1.14游戏胜利界面至此,已经完成整个游戏基本的内部相关功能模块的运算,接下来实现用户的交互部分的功能。5.3鼠标交互功能的实现对于用户交互的实现,这里选择鼠标交互方式。下面简单描述一下通过鼠标交互方式实现的功能。鼠标选取两个图案方块后,程序将自动判断所选定的两个方块是否能进行抵消操作,能则进行抵消操作。在游戏过程中,我们不断重复上面描述的功能,直到游戏的胜利结束。下面将鼠标事件处理工作归纳为如图1.14所示的流程。图1.15对于鼠标交互功能的实现,可以通过ClassWizard对鼠标左键被按下时触发的命令消息WM_LBUTTONDOWN进行拦截,并重写该消息的处理函数OnLButtonDown(),其程序清单如下所示。voidCMyDlg::OnLButtonDown(UINTnFlags,CPointpoint){ //1.计算鼠标点击方块的的位置 intx=point.x/FRONTWIDTH+(point.x%FRONTWIDTH?1:0)-1; inty=point.y/FRONTHEIGHT+(point.y%FRONTHEIGHT?1:0)-1; //2.在游戏区域内并且该区域还有该区域不是空的区域 if(x<m_nCol&&y<m_nRow&&m_map[y*m_nCol+x]!=BLANK_STATE) { //3.假设尚未记录第一个方块 if(m_nX1==BLANK_STATE) { //4.记录第一个方块的位置 m_nX1=x; m_nY1=y; //获取程序框架的设备环境 CDC*pWinDC=GetDC(); //临时绘制点中的方块外框 //只绘屏幕不载入内存位图 CPenmyPen; CPen*pOldPen; myPen.CreatePen(PS_SOLID,4,RGB(255,0,0)); pOldPen= pWinDC->SelectObject(&myPen); //方块外框绘制,线条环绕绘制框架 pWinDC->MoveTo(x*FRONTWIDTH,y*FRONTHEIGHT); pWinDC->LineTo(x*FRONTWIDTH,(y+1)*FRONTHEIGHT); pWinDC->LineTo((x+1)*FRONTWIDTH,(y+1)*FRONTHEIGHT); pWinDC->LineTo((x+1)*FRONTWIDTH,y*FRONTHEIGHT); pWinDC->LineTo(x*FRONTWIDTH,y*FRONTHEIGHT); //现场恢复 pWinDC->SelectObject(pOldPen); } else { //5.判断是否点击的方块非本身,是否点击同一种动物 if((m_nX1!=x||m_nY1!=y)&& m_map[m_nY1*m_nCol+m_nX1]==m_map[y*m_nCol+x] ) { //6.检测是否可以消除 if(IsLink(m_nX1,m_nY1,x,y)) { //7.数据清理 m_map[m_nY1*m_nCol+m_nX1]=BLANK_STATE; m_map[y*m_nCol+x]=BLANK_STATE; } } //8.清空记录方块的值 m_nX1=BLANK_STATE; m_nY1=BLANK_STATE; //通知重绘 Invalidate(FALSE); } } //察看是否已经胜利 if(IsWin()) { MessageBox("恭喜您胜利闯关,即将开始新局"); StartNewGame(); }}按照预先设计出的鼠标事件处理流程,上面已经将它转换成具体的实现代码。下面将按照流程的子功能模块的划分方式,对整个功能模块的具体协调和实现过程进行简单的描述。(1)首先,利用鼠标的当前坐标位置point对每个小单元方块的宽度FRONTWIDTH和高度FRONTHEIGHT分别取模,获取当前鼠标落点所在的游戏区域的具体行列数(x,y)。(2)判断出该行列数(x,y)是否符合条件。保证运算出来的行数x和列数y的预定义区域最大的行数m_nCol和列数m_nRow内,并且点击的区域状态不是空白方块区域BLANK_STATE(3)对判断此次鼠标书剑的选取是否与第一个方块的选取一样,只需通过用于记录第一个被选中的方块的行列数的成员变量m_nX1是否为有效即可。这里将m_nX1以及m_nY1来记录它所在的行、列数,并且每次经过判断后都会将它们的状态恢复为空白无选中状态BLANK_STATE。关于这两个用作记录第一个选中图案方块行列数的成员变量,在对话框类中的具体定义如下所示: int m_nX1;//鼠标选中的记录方块列数 int m_nY1; //鼠标选中的记录方块行数(4)对于本次选中的方块为第一选中的情况,先用m_nX1和m_nY1对当前的选中方块位置做记录,然后直接在屏幕的该区域绘制图像,为该方块区域添加一个红色的矩形外边框,用以提示用户当前的第1个图案方块选中所在的位置。需要注意的是,对于标记方块的加亮边框绘制是通过GetDC()函数来获取对话框窗体(屏幕)的设备环境,对绘制的图像数据没有作历史记录的方式来绘制的。(5)在这一处理中,对该选定方块作一些判断,以便更高效地处理。判断选中的方块与前一方块是否为同一图案方块,并且此次选择不与上一次选定的方块为同一方块,然后才跳到下一步对两个选定的方块是否可以抵消的流程中去。(6)调用前面已经实现的答功能函数IsLink()来判断当前所选定的两个图案方块是否可以抵消。(7)如果可以抵消,对选中的两个方块在内部核心地图对应的数据状态作适当的修改,将它们的状态记作已经被销毁的空方块状态BLANK_STATE。(8)完成第二个图案的选取与相关的功能操作后,我们需要前面已经选去第1个方块位置的记录作清理工作,以便下一个新方块的选择。(9)最后,判断此次的鼠标操作是否已经胜利结束,如果是则给予用户提示,然后重新开适新的一关。6.绘图功能的实现在完成以上所有的交互以及内部数据关联的运算处理后,最后要将这些数据展现到屏幕上。6.1位图图像的准备首先,准备好一个带有不同动物种以及一个3D边框效果的位图,如图1.15所示。通过资源编辑器将它们引入到项目中来,并将它们的ID分别命名为IDB_BMP_ANIMAL和IDB_BITMAP_3DFRAMES。图1.16word文档可自由复制编辑6.2绘图方案的设计对于游戏的绘制实现,这里采用内存位图映射的方式,先将整个游戏区域的图像绘制到内存位图中,然后再一次性地将它拷贝到屏幕上予以显示,如图1.16所示图1.176.3绘图资源的载入与初始化根据图1.16所示的描述方案,可以在内存创建两个内存位图,并对它们的图像进行载入。在需要使用的时候,则可以从这些内存位图中直接去拷贝,并绘制到游戏区域内存位图中去,接下来添加关于绘图的成员变量,如下所示。//内存位图属性组 CDC m_mem3DBkDC;//3D框架的内存设备环境 CBitmapm_mem3DBkBmp;//3D框架的内存位图 CDC m_memAnimalDC;//动物图像的内存设备环境 CBitmapm_memAnimalBmp;//动物图像的内存位图 CDC m_MemDC;//游戏区域内存设备环境 CBitmapm_memBitmap;//游戏区域内存位图这里,对3D框架位图以及动物图案位图分别创建了对应的设备环境m_mem3DBkDC和m_memAnimalDC,并且位它们分配了关联的内存位图变量m_mem3DBkBmp和m_memAnimalBmp。而对于游戏区域的内存绘制,亦为它创建了一个内存设备环境m_MemDC以及关联的内存位图m_memBitmap。在完成以上工作后,需要在程序开始运行的时候,一次行对它们进行适当的初始化。可以将这些绘图的具体初始化加载在CMyDlg对话框类的初始话函数OnInitDialog中,代码如下所示。 //获取程序框架的设备环境 CDC*pWinDC=GetDC(); //内存设备环境以及内存位图的创建,初始化,关联 //3D方块边框图样内存位图 m_mem3DBkDC.CreateCompatibleDC(pWinDC); m_mem3DBkBmp.LoadBitmap(IDB_BITMAP_3D_FRAMES); m_mem3DBkDC.SelectObject(&m_mem3DBkBmp); //动物图样内存位图 m_memAnimalDC.CreateCompatibleDC(pWinDC); m_memAnimalBmp.LoadBitmap(IDB_BMP_ANIMAL); m_memAnimalDC.SelectObject(&m_memAnimalBmp); //整个游戏区域内存位图 m_MemDC.CreateCompatibleDC(pWinDC); m_memBitmap.CreateCompatibleBitmap(pWinDC, m_nCol*FRONTWIDTH+5, m_nRow*FRONTHEIGHT+5); m_MemDC.SelectObject(&m_memBitmap); //开始一个新的游戏 StartNewGame(); //放在最桌面的前面显示 HWNDhWnd=::AfxGetMainWnd()->m_hWnd; ::SetWindowPos(hWnd,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE); //Settheiconforthisdialog.Theframeworkdoesthisautomatically //whentheapplication'smainwindowisnotadialog SetIcon(m_hIcon,TRUE); //Setbigicon SetIcon(m_hIcon,FALSE); //Setsmallicon //TODO:Addextrainitializationhere returnTRUE;//returnTRUEunlessyousetthefocustoacontrol在上面的代码中,现获取该程序的屏幕设备环境,然后在将前面提到的3个内存设备环境以及关联的内存位图与该屏幕设备环境兼容,而对于两个用于存储外部位图图像的内存位图,则调用LoadBitmap()函数对他们相应的位图资源进行载入以及相关的初始化工作。6.4游戏区域的绘制在完成绘图物件的初始化工作后,接下来就可以对整个游戏区域的绘制进行实现,对整个游戏区域的绘制,可以将封装在GameDraw()函数里,其代码清单如下所示。voidCMyDlg::GameDraw(CDC*pDC){ //绘制背景颜色pDC->FillSolidRect(0,0,m_nCol*FRONTWIDTH+5,m_nRow*FRONTHEIGHT+5,BKCOLOR); for(inti=0;i<m_nRow;i++) { for(intj=0;j<m_nCol;j++) { if(m_map[i*m_nCol+j]==BLANK_STATE) { continue; } //绘制方块边框 pDC->BitBlt(j*FRONTWIDTH,i*FRONTHEIGHT, BKWIDTH,BKHEIGHT, &m_mem3DBkDC, 0,BKHEIGHT, SRCCOPY); //绘制方块 //因为要使得效果透明,所以由图样的底色以及表面两部分构成 pDC->BitBlt(j*FRONTWIDTH,i*FRONTHEIGHT, FRONTWIDTH-2,FRONTHEIGHT-12, &m_memAnimalDC, FRONTWIDTH-2,m_map[i*m_nCol+j]*(FRONTHEIGHT-12), SRCAND); pDC->BitBlt(j*FRONTWIDTH,i*FRONTHEIGHT, FRONTWIDTH-2,FRONTHEIGHT-12, &m_memAnimalDC, 0,m_map[i*m_nCol+j]*(FRONTHEIGHT-12), SRCPAINT); } }}在上面程序中,先调用FillSolidRect()函数来绘制整个游戏区域的背景,在对游戏区域中有动物图案的方块进行3D边框的绘制,绘制的方法示从3D边框的内存位图中拷贝,然后在根据内核地图中每一个方框区域的图案物种从动物内存位图m_memAnimalBmp中通过与它关联的m_memAnimalDC进行动物图案的拷贝。7.背景音乐功能的实现在游戏过程中,播放背景音乐这在一定程度上能够增加用户对游戏的沉侵感。对声音模块信息的管理在程序中是通过API中的PlaySound函数来实现的。首先选择一段.wav音乐在ResourceView界面插入WAVE资源并引入该段音乐,并设置属性为IDR_WAVE1,在菜单中添加音乐菜单和子菜单播放与暂停。同上所述,给播放菜单添加消息映射,并添加下列代码:PlaySound(MAKEINTRESOURCE(IDR_WAVE1),AfxGetResourceHandle(),SND_ASYNC|SND_RESOURCE|SND_NODEFAULT|SND_LOOP);给暂停菜单添加消息映射,并添加下列代码:PlaySound(NULL,NULL,SND_FILENAME);因为PlaySound函数体被编译到Winmm.lib库文件中,点击工程—设置,选择连接,在对象/库模块填入winmm.lib,这样就可在点击播放菜单播放背景音乐,点击暂停菜单停止背景音乐了。8.总结经过一个学期对《C++实用教程》的学习,我学习到了基本的理论知识,了解到了C++语言程序设计的思想,这些知识都为我的课程实践和进一步的学习打下了坚实的基础。在为期近两周的C++课程设计中,我体会颇多,学到了很多东西。我加强了对C++程序设计这门课程的认识,并且复习了自己以前学习到的知识。这些都使得我对计算机语言的学习有了更深入的认识!总之,通过这次课程设计,我收获颇丰,相信会为自己以后的学习和工作带来很大的好处。像小游戏程序设计,经历了平时在课堂和考试中不会出现的问题和考验。而这些问题,这并不是我们平时只靠课本,就可以轻易解决的。所以,锻炼了我们挑战难题,学会用已掌握的知识去解决具体问题的能力,进一步培养了独思考问题和解决问题的能力。特别是学会了在Visual
C++中如何调试程序的方法。当然,老师的指导和同学的帮助也是不可忽视的,他们给了我许多提示和帮助,教会了我编译复杂程序的方法。本文用visualc++来设计与实现简单的连连看游戏的基本功能,对该游戏的算法以及游戏图案的绘制进行详细的介绍,其中核心内容包括图案方块的销毁判断,游戏胜利判断以及整个游戏用户交换功能的实现。在制作过程中学会了位图的引入,对话框背景的设置,背景音乐的播放,对话框显示菜单的方法等,还加深了对MFC功能的理解,对各个类的函数功能的理解,对事件的消息映射的理解。此课程设计算法比较简单,运行速度快。参考文献1.GeorgeShepherd/DavidKruglinski著,潘爱民译Microsoft®VisualC++.NET技术内幕(第6版),,清华大学出版社,2.杨永国编,VisualC++6.0实用教程.清华大学出版社,20043.唐俊明编,VisualC++6.0编程实例与技巧.高等教育出版,20024.潘锦平编,软件系统开发技术.西安电子科技大学出版社,19975.朱继满等译.,ProgrammingMicrosoftVisualC++技术内幕(第五版),北京希望电子出版社,20016.宋坤等编,VisualC++开发技术大全,人民邮电出版社,20077.ErichGamma等著,李英军等译,机械工业出版社,设计模式——可复用面向对象软件的基础8.严蔚敏等编,数据结构,清华大学出版社,20069.JohnE.Swanke著,VisualMFC编程实例,机械工业出版社,200010.侯俊杰编著,深入浅出MFC,华中科技大学出版社11.ABeginner'sGuidetoPointers,AndrewPeace/cpp/pointers.asp附录:源代码//课程设计(连连看)Dlg.cpp:implementationfile//#include"stdafx.h"#include"课程设计(连连看).h"#include"课程设计(连连看)Dlg.h"#include"mmsystem.h"#ifdef_DEBUG#definenewDEBUG_NEW#undefTHIS_FILEstaticcharTHIS_FILE[]=__FILE__;#endif#defineBKCOLORRGB(128,128,128) //背景颜色#defineFRONTWIDTH (39+2) //前面方块的宽度#defineFRONTHEIGHT (39+12) //前面方块的高度#defineBKWIDTH 46 //背景方块的宽度#defineBKHEIGHT56 //背景方块的高度#defineROWCOUNT4 //行数#defineCOLCOUNT6 //列数#defineBLANK_STATE-1//空方块(没有任何动物)///////////////////////////////////////////////////////////////////////////////CAboutDlgdialogusedforAppAboutclassCAboutDlg:publicCDialog{public: CAboutDlg();//DialogData //{{AFX_DATA(CAboutDlg) enum{IDD=IDD_ABOUTBOX}; //}}AFX_DATA //ClassWizardgeneratedvirtualfunctionoverrides //{{AFX_VIRTUAL(CAboutDlg) protected: virtualvoidDoDataExchange(CDataExchange*pDX);//DDX/DDVsupport //}}AFX_VIRTUAL//Implementationprotected: //{{AFX_MSG(CAboutDlg) //}}AFX_MSG DECLARE_MESSAGE_MAP()};CAboutDlg::CAboutDlg():CDialog(CAboutDlg::IDD){ //{{AFX_DATA_INIT(CAboutDlg) //}}AFX_DATA_INIT}voidCAboutDlg::DoDataExchange(CDataExchange*pDX){ CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CAboutDlg) //}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(CAboutDlg,CDialog) //{{AFX_MSG_MAP(CAboutDlg) //Nomessagehandlers //}}AFX_MSG_MAPEND_MESSAGE_MAP()///////////////////////////////////////////////////////////////////////////////CMyDlgdialogCMyDlg::CMyDlg(CWnd*pParent/*=NULL*/) :CDialog(CMyDlg::IDD,pParent){ //{{AFX_DATA_INIT(CMyDlg) //NOTE:theClassWizardwilladdmemberinitializationhere //}}AFX_DATA_INIT //NotethatLoadIcondoesnotrequireasubsequentDestroyIconinWin32 //记录方块置为无效状态 m_nY1=BLANK_STATE; m_nX1=BLANK_STATE;//初始化行列数 m_nRow=ROWCOUNT; m_nCol=COLCOUNT; //根据行列数动态分配内核数据数组空间 m_map=newint[m_nRow*m_nCol]; m_hIcon=AfxGetApp()->LoadIcon(IDR_MAINFRAME);}voidCMyDlg::DoDataExchange(CDataExchange*pDX){ CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CMyDlg) //NOTE:theClassWizardwilladdDDXandDDVcallshere //}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(CMyDlg,CDialog) //{{AFX_MSG_MAP(CMyDlg) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_WM_LBUTTONDOWN() ON_COMMAND(ID_MENUITEM32773,OnMenuitem32773) ON_COMMAND(ID_MENUITEM32774,OnMenuitem32774) ON_COMMAND(ID_MENUITEM32771,OnMenuitem32771) ON_COMMAND(ID_MENUITEM32772,OnMenuitem32772) //}}AFX_MSG_MAPEND_MESSAGE_MAP()///////////////////////////////////////////////////////////////////////////////CMyDlgmessagehandlersBOOLCMyDlg::OnInitDialog(){ CDialog::OnInitDialog(); //Settheiconforthisdialog.Theframeworkdoesthisautomatically //whentheapplication'smainwindowisnotadialog SetIcon(m_hIcon,TRUE); //Setbigicon SetIcon(m_hIcon,FALSE); //Setsmallicon //获取程序框架的设备环境 CDC*pWinDC=GetDC(); //内存设备环境以及内存位图的创建,初始化,关联 //3D方块边框图样内存位图 m_mem3DBkDC.CreateCompatibleDC(pWinDC); m_mem3DBkBmp.LoadBitmap(IDB_BITMAP_3D_FRAMES); m_mem3DBkDC.SelectObject(&m_mem3DBkBmp); //动物图样内存位图 m_memAnimalDC.CreateCompatibleDC(pWinDC); m_memAnimalBmp.LoadBitmap(IDB_BMP_ANIMAL); m_memAnimalDC.SelectObject(&m_memAnimalBmp); //整个游戏区域内存位图 m_MemDC.CreateCompatibleDC(pWinDC); m_memBitmap.CreateCompatibleBitmap(pWinDC, m_nCol*FRONTWIDTH+5, m_nRow*FRONTHEIGHT+5); m_MemDC.SelectObject(&m_memBitmap); //开始一个新的游戏 StartNewGame(); //放在最桌面的前面显示 HWNDhWnd=::AfxGetMainWnd()->m_hWnd; ::SetWindowPos(hWnd,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE); returnTRUE;//returnTRUEunlessyousetthefocustoacontrol}voidCMyDlg::OnSysCommand(UINTnID,LPARAMlParam){ if((nID&0xFFF0)==IDM_ABOUTBOX) { CAboutDlgdlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID,lParam); }}//Ifyouaddaminimizebuttontoyourdialog,youwillneedthecodebelow//todrawtheicon.ForMFCapplicationsusingthedocument/viewmodel,//thisisautomaticallydoneforyoubytheframework.voidCMyDlg::OnPaint(){CPaintDCdc(this);//devicecontextforpainting //先将整个游戏区域的图像绘制到内存位图 GameDraw(&m_MemDC); //将内存位图中绘制好的图像一次性拷贝到屏幕 dc.BitBlt(0,0,m_nCol*FRONTWIDTH,m_nCol*FRONTHEIGHT,&m_MemDC,0,0,SRCCOPY);}//Thesystemcallsthistoobtainthecursortodisplaywhiletheuserdrags//theminimizedwindow.HCURSORCMyDlg::OnQueryDragIcon(){ return(HCURSOR)m_hIcon;}CMyDlg::~CMyDlg(){ //释放动态数组空间 delete[]m_map;}voidCMyDlg::StartNewGame(){ //初始化地图,将地图中所有方块区域位置置为空方块状态 for(intiNum=0;iNum<(m_nCol*m_nRow);iNum++) { m_map[iNum]=BLANK_STATE; } //部下随机种子 srand(time(NULL)); //生成随机地图 //将所有匹配成对的动物物种放进一个临时的地图中 CDWordArraytmpMap; for(inti=0;i<(m_nCol*m_nRow)/6;i++) for(intj=0;j<6;j++) tmpMap.Add(i); //每次从上面的临时地图中取走(获取后并在临时地图删除) //一个动物放到地图的空方块上 for(i=0;i<m_nRow*m_nCol;i++) { //随机挑选一个位置 intnIndex=(int(rand()*0.1+rand()*0.01+rand()))%tmpMap.GetSize(); //获取该选定物件放到地图的空方块 m_map[i]=tmpMap.GetAt(nIndex); //在临时地图除去该动物 tmpMap.RemoveAt(nIndex); } //更新显示 Invalidate(TRUE);}BOOLCMyDlg::IsLink(intx1,inty1,intx2,inty2){//X直连方式 if(x1==x2) { if(X1_Link_X2(x1,y1,y2)) returnTRUE; } //Y直连方式 elseif(y1==y2) { if(Y1_Link_Y2(x1,x2,y1)) returnTRUE; } //一个转弯直角的联通方式 if(OneCornerLink(x1,y1,x2,y2)) { returnTRUE; } //两个转弯直角的联通方式 elseif(TwoCornerLink(x1,y1,x2,y2)) { returnTRUE; } returnFALSE;}BOOLCMyDlg::X1_Link_X2(intx,inty1,inty2){//保证y1的值小于y2 if(y1>y2) { //数据交换 intn=y1; y1=y2; y2=n; } //直通 for(inti=y1+1;i<=y2;i++) { if(i==y2) returnTRUE; if(m_map[i*m_nCol+x]!=BLANK_STATE) break; } //左通 if(XThrough(x-1,y1,FALSE)&&XThrough(x-1,y2,FALSE)) returnTRUE; //右通 if(XThrough(x+1,y1,TRUE)&&XThrough(x+1,y2,TRUE)) returnTRUE; returnFALSE;}//Y直接连通BOOLCMyDlg::LineX(intx,inty1,inty2){if(y1>y2) { inty=y1; y1=y2; y2=y; } for(inty=y1;y<=y2;y++) { if(m_map[y*m_nCol+x]!=BLANK_STATE) returnFALSE; if(y==y2) returnTRUE; } returnFALSE;}BOOLCMyDlg::LineY(intx1,intx2,inty){if(x1>x2) { intx=x1; x1=x2; x2=x; } for(intx=x1;x<=x2;x++) { if(m_map[y*m_nCol+x]!=BLANK_STATE) returnFALSE; if(x==x2) returnTRUE; } returnFALSE;}BOOLCMyDlg::OneCornerLink(intx1,inty1,intx2,inty2){ if(x1>x2) { intn=x1; x1=x2; x2=n; n=y1; y1=y2; y2=n; } if(y2<y1) { if(LineY(x1+1,x2,y1)&&LineX(x2,y1,y2+1)) returnTRUE; if(LineY(x2-1,x1,y2)&&LineX(x1,y2,y1-1)) returnTRUE; returnFALSE; } else { if(LineY(x1+1,x2,y1)&&LineX(x2,y1,y2-1)) returnTRUE; if(LineY(x2-1,x1,y2)&&LineX(x1,y2,y1+1)) returnTRUE; returnFALSE; } returnFALSE;}BOOLCMyDlg::TwoCornerLink(intx1,inty1,intx2,inty2){ if(x1>x2) { intn=x1; x1=x2; x2=n; n=y1; y1=y2; y2=n; } //右通 if(XThrough(x1+1,y1,TRUE)&&XThrough(x2+1,y2,TRUE)) returnTRUE; //左通 if(XThrough(x1-1,y1,FALSE)&&XThrough(x2-1,y2,FALSE)) returnTRUE; //上通 if(YThrough(x1,y1-1,FALSE)&&YThrough(x2,y2-1,FALSE)) returnTRUE; //下通 if(YThrough(x1,y1+1,TRUE)&&YThrough(x2,y2+1,TRUE)) returnTRUE; //右 for(intx=x1+1;x<m_nCol;x++) { if(m_map[y1*m_nCol+x]>-1) break; if(OneCornerLink(x,y1,x2,y2)) returnTRUE; } //左 for(x=x1-1;x>-1;x--) { if(m_map[y1*m_nCol+x]!=BLANK_STATE) break; if(OneCornerLink(x,y1,x2,y2)) returnTRUE; } //上 for(inty=y1-1;y>-1;y--) { if(m_map[y*m_nCol+x1]!=BLANK_STATE) break; if(OneCornerLink(x1,y,x2,y2)) returnTRUE; } //下 for(y=y1+1;y<m_nRow;y++) { if(m_map[y*m_nCol+x1]!=BLANK_STATE) break; if(OneCornerLink(x1,y,x2,y2)) returnTRUE; } returnFALSE;}BOOLCMyDlg::XThrough(intx,inty,BOOLbAdd){if(bAdd) { for(inti=x;i<m_nCol;i++) if(m_map[y*m_nCol+i]!=BLANK_STATE) returnFALSE; } else { for(inti=0;i<=x;i++) if(m_map[y*m_nCol+i]!=BLANK_STATE) returnFALSE; } returnTRUE;}BOOLCMyDlg::YThrough(intx,inty,BOOLbAdd){if(bAdd) { for(inti=y;i<m_nRow;i++) if(m_map[i*m_nCol+x]!=BLANK_STATE) returnFALSE; } else { for(inti=0;i<=y;i++) if(m_map[i*m_nCol+x]!=BLANK_STATE) returnFALSE; } returnTRUE;}BOOLCMyDlg::IsWin(){//检测所有是否尚有非未被消除的方块 //(非BLANK_STATE状态) for(inti=0;i<m_nRow*m_nCol;i++) { if(m_map[i]!=BLANK_STATE) { returnFALSE; } } returnTRUE;}voidCMyDlg::OnLButtonDown(UINTnFlags,CPointpoint){ //TODO:Addyourmessagehandlercodehereand/orcalldefault //○1.计算鼠标点击方块的的位置 intx=point.x/FRONTWIDTH+(point.x%FRONTWIDTH?1:0)-1; inty=point.y/FRONTHEIGHT+(point.y%FRONTHEIGHT?1:0)-1; //○2.在游戏区域内并且该区域还有该区域不是空的区域 if(x<m_nCol&&y<m_nRow&&m_map[y*m_nCol+x]!=BLANK_STATE) { //○3.假设尚未记录第一个方块 if(m_nX1==BLANK_STATE) { //○4记录第一个方块的位置 m_nX1=x; m_nY1=y; //获取程序框架的设备环境 CDC*pWinDC=GetDC(); //临时绘制点中的方块外框 //只绘屏幕不载入内存位图 CPenmyPen; CPen*pOldPen; myPen.CreatePen(PS_SOLID,4,RGB(255,0,0)); pOldPen= pWinDC->SelectObject(&myPen); //方块外框绘制,线条环绕绘制框架 pWinDC->MoveTo(x*FRONTWIDTH,y*FRONTHEIGHT); pWinDC->LineTo(x*FRONTWIDTH,(y+1)*FRONTHEIGHT); pWinDC->
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年土地整治项目土地抵押合同范例3篇
- 2024年某物业管理公司与某小区关于物业服务合同
- 房屋租赁合同模板合集五篇
- 七年级第一学期生物教案模板
- 跟岗实习工作总结范文
- 举行春游活动方案
- 配音比赛策划书
- 店长述职报告15篇
- 学生竞选演讲稿怎么写才能吸引人?【5篇】
- 投标承诺书集锦15篇
- 社区居家养老方案
- 2024年英语专业四级考试真题及详细答案
- 输液巡视不及时品管圈课件
- 中班自主游戏总结汇报
- 加油站防偷盗与防灾安全培训
- 玻璃制造企业的管理与技术创新
- 《护理病人隐私保护措施》
- MHT:中小学生心理健康检测(含量表与评分说明)
- 企业战略管理顾问聘用合同
- 贵州壮丽山水文化之旅
- 辽宁省朝阳市朝阳县2023-2024学年九年级上学期期末数学试题
评论
0/150
提交评论