1、嵌入式系统课程设计连连看游戏设计与分析作 者 姓 名: 专业、班级 : 学 号 : 指 导 教 师: 完 成 日 期: 第 1 页目录 引言1. 系统分析与总体设计.11.1 项目概述.1.1.1 项目概要1.1.2 项目的意义.1.2.3 主要问题.1.2 总体设计.1.2.1 总体结构图.1.2.2 系统功能.1.2.3 系统结构及相关模块2. 系统的详细设计.2.1 初始化游戏界面.2.2 图片的选择.2.3 图片的判断与消除.2.4 游戏的结果.3.系统的实现与调试.3.1 调试过程.3.2 运行结果第 2 页1、 系统分析与总体设计1.1 项目概述1.1.1 项目概要“连连看“是近几
2、年流行于网络的一种益智类休闲小游戏。它主要通过在游戏界面内连接相同图案来进行消除,以最终完全消除游戏界面内的图案为游戏完成的标准。这项小游戏操作简单,只需用鼠标进行点击操作即可,并且对玩家观察力、判断力、反应能力起到很好的煅炼作用,故一经推出就受到了广大玩家的喜爱。1.1.2 项目的意义随着社会节奏的加快,平常工作的竞争强度也加大,生活的压力也跟着加重。所以休息时或下班后大家都需要个休闲的娱乐工具,来放松自己,缓解自己的压力,消除紧张的疲劳状态。连连看游戏是一种意趣休闲的小游戏,不仅能调节精神,还能在游戏中锻炼我们的眼力视野,注意力的专心的程度,开发我们的思维能力,同时可以充实自己,向高等级挑
3、战,培养我们面对困难时自己所具有攻克困难的信心。当今基于 EVC4.0 编程技术的游戏开发十分流行,被游戏开发者所普遍应用。而“连连看”是近来网络上非常流行的一种休闲游戏,它对电脑配置要求不高,娱乐性强,简单易玩。目前大学生课程涉及基于 EVC 编程技术游戏开发方向的相对较少,这次通过连连看游戏的设计开发将对理解 EVC 技术以及 EVC技术在游戏方面的应用起到很大的帮助作用,同时为 EVC+编程技术及游戏设计打下坚实的基础。1.1.3 主要问题开始制作游戏时,主要要解决的问题有以下几个方面:如何设置整个游戏的界面;如何控制连连看游戏中随机图片的生成且每种图片必须为偶数个;游戏开始后,判断鼠标
4、两次点击的图片能否消去,即图片是否相同且图片之间路径的判断. 第 3 页1.2 总体设计1.2.1 总体结构图连连看游戏初始化游戏界面选择图片图片的判断与消除游戏结束的判断创建窗口加载绘图资源图片的判断图片的消除判断游戏结束 判断游戏死锁给出提示信息图 1.11.2.2 系统功能(1) 初始化游戏界面该部分主要由执行窗口创建函数及位图加载函数来实现。通过数据的初始化及位图资源的加载为用户呈现一个游戏初始的界面。(2) 图 片 的 选 择该 功 能 主 要 由 鼠 标 来 完 成 。 在 OnLButtonDown()事 件 函 数 中 通 过 鼠 标的 点 击 事 件 选 取 所 要 消 除
5、的 两 个 相 同 图 片 。(3) 图 形 的 判 断 与 消 除对 于 第 (2)步 所 选 的 两 个 图 片 , 对 其 连 通 性 进 行 判 断 : 如 果 两 图 片 直 线连 通 , 则 相 互 消 去 ; 如 果 两 图 片 连 接 为 一 个 拐 点 且 相 通 , 则 相 互 消 去 ; 如 果两 图 片 连 接 为 两 个 拐 点 且 相 通 , 则 相 互 消 去 ; 否 则 , 不 能 消 去 。(4) 判 断 游 戏 是 否 死 锁 或 结 束如 果 所 有 的 图 片 全 部 消 去 , 则 提 示 “游 戏 结 束 ! ”的 信 息 。 当 游 戏 玩第 4
6、页家 不 可 能 在 消 去 任 意 两 个 图 片 时 , 游 戏 进 入 死 锁 状 态 。 此 时 提 示 相 关 信 息 。1.2.3 系 统 的 结 构 及 相 关 模 块图 1.22、 系 统 的 详 细 设 计2.1 初 始 化 游 戏 页 面首先调用 CenterWindow()函数创建一个居中的窗口,再执行m_bitmap.LoadBitmap()函数来加 载 指 定 的 位 图 资 源 , 然 后 通 过 调 用m_MemDC.CreateCompatibleDC() 创 建 一 个 与 指 定 设 备 兼 容 的 内 存 设 备 上 下文 环 境 ( DC) , 再 调
7、用 CreateCompatibleBitmap()函 数 创 建 与 指 定 的 设 备环 境 相 关 的 设 备 兼 容 的 位 图 ; 最 后 调 用 FillMemDC()函 数 填 充 所 创 建 的 窗口 。 该 部 分 的 实 现 代 码 下 :连连看游戏界面显示模块显示游戏界面显示提示信息鼠标控制模块选择图片控制游戏开始与结束图像处理模块图片识别图片判断图片消除第 5 页BOOL CPocketLianDlg:OnInitDialog()CDialog:OnInitDialog();SetIcon(m_hIcon, TRUE);SetIcon(m_hIcon, FALSE);/
8、创 建 一 个 居 中 的 窗 口CenterWindow(GetDesktopWindow();/加 载 指 定 的 位 图 资 源m_bitmap.LoadBitmap(IDB_BITMAP_129);CClientDC dc(this);/创 建 一 个 与 指 定 设 备 兼 容 的 内 存 设 备 上 下 文 环 境m_MemDC.CreateCompatibleDC(CBitmap bitmap;/创 建 与 指 定 的 设 备 环 境 相 关 的 设 备 兼 容 的 位 图bitmap.CreateCompatibleBitmap(m_MemDC.SelectObject(int
9、 n=GetTickCount();srand(n);/time(NULL);CDWordArray arPlayer;for(int i=0;iSelectObject(/方块外框绘制,线条环绕绘制框架pWinDC-MoveTo(x*FRONTWIDTH,y*FRONTHEIGHT);pWinDC-LineTo(x*FRONTWIDTH,(y+1)*FRONTHEIGHT);第 8 页pWinDC-LineTo(x+1)*FRONTWIDTH,(y+1)*FRONTHEIGHT);pWinDC-LineTo(x+1)*FRONTWIDTH,y*FRONTHEIGHT);pWinDC-Line
10、To(x*FRONTWIDTH,y*FRONTHEIGHT);/现场恢复pWinDC-SelectObject(pOldPen);else /5.判断是否点击的方块非本身, 是否点击同一种动物if(m_nX1!=x|m_nY1!=y)m_mapy*m_nCol+x=BLANK_STATE;/8.清空记录方块的值m_nX1=BLANK_STATE; m_nY1=BLANK_STATE;/通知重绘Invalidate(FALSE);第 9 页/察看是否已经胜利if(IsWin()MessageBox(“游戏结束“);StartNewGame();按照预先设计出的鼠标事件处理流程,上面已经将它转换成
11、具体的实现代码。下面将按照流程的子功能模块的划分方式,对整个功能模块的具体协调和实现过程进行简单的描述。 (1)首先,利用鼠标的当前坐标位置 point 对每个小单元方块的宽度 FRONTWIDTH 和高度 FRONTHEIGHT 分别取模,获取当前鼠标落点所在的游戏区域的具体行列数(x,y) 。(2)判断出该行列数(x,y)是否符合条件。保证运算出来的行数 x 和列数y 的预定义区域最大的行数 m_nCol 和列数 m_nRow 内,并且点击的区域状态不是空白方块区域 BLANK_STATE(3)对判断此次鼠标书剑的选取是否与第一个方块的选取一样,只需通过用于记录第一个被选中的方块的行列数的
12、成员变量 m_nX1 是否为有效即可。这里将 m_nX1 以及 m_nY1 来记录它所在的行、列数,并且每次经过判断后都会将它们的状态恢复为空白无选中状态 BLANK_STATE。关于这两个用作记录第一个选中图案方块行列数的成员变量,在对话框类中的具体定义如下所示:int m_nX1; /鼠标选中的记录方块列数int m_nY1; /鼠标选中的记录方块行数(4)对于本次选中的方块为第一选中的情况,先用 m_nX1 和 m_nY1 对当前的选中方块位置做记录,然后直接在屏幕的该区域绘制图像,为该方块区域添加一个红色的矩形外边框,用以提示用户当前的第 1 个图案方块选中所在的位置。需要注意的是,对
13、于标记方块的加亮边框绘制是通过 GetDC()函数来获取对话框窗体(屏幕)的设备环境,对绘制的图像数据没有作历史记录的方式来绘制的。(5)在这一处理中,对该选定方块作一些判断,以便更高效地处理。判断第 10 页选中的方块与前一方块是否为同一图案方块,并且此次选择不与上一次选定的方块为同一方块,然后才跳到下一步对两个选定的方块是否可以抵消的流程中去。(6)调用前面已经实现的答功能函数 IsLink()来判断当前所选定的两个图案方块是否可以抵消。(7)如果可以抵消,对选中的两个方块在内部核心地图对应的数据状态作适当的修改,将它们的状态记作已经被销毁的空方块状态 BLANK_STATE。(8)完成第
14、二个图案的选取与相关的功能操作后,我们需要前面已经选去第 1 个方块位置的记录作清理工作,以便下一个新方块的选择。(9)最后,判断此次的鼠标操作是否已经胜利结束,如果是则给予用户提示,然后重新开适新的一关。2.3 图 形 的 判 断 与 消 除对于选中的两个图片的销毁,它们必须符合下面 3 个条件:(1)选中的两个图片图案相同。(2)选中的两个图片之间没有障碍物阻碍的情况下,可以用若干个垂直的直线线段连接起来。(3)这些将它们连接起来的直线线段的折点不超过两个(连接线由 x 轴和 y 轴的平行线组成) 。现在针对(2)和(3)进行分析,同种物件的连接方式大致可以分成以下3 种:(1) 直接方式
15、(2) 有一个折点的垂直线段连接。(3) 有两个折点的垂直线段连接.。1. 直接连接方式在直接连接方式中,必须要求所选定的两个方块在同一水平直线上(可以为x 方向或 y 方向) ,并且两个方块之间没有任何其他图案方块。2.一个这点连接方式所选定的两个方块如果通过折点的方式连接,那么对于折点来说,每个折第 11 页点必定有且至少有一个坐标(x 或 y)是和其中一个目标点相同的,即折点必定在两个目标点所在的 x 方向或 y 方向的直线上。此外,对于一个折点连接的情况,折点应该为第一个选中方块的横向线或纵向线与第二个选中方块的纵向线和横向线相交而得出。3.两个折点的连接方式这种方式的两个折点所连成的
16、直线与两物件的直接连线可以构成平行线,因此可以根据这个规律,将这条水平线在游戏区域允许的条件上下移动,然后通过判断整条带垂直折线点的曲线之间有无障碍物方式来确定是否可以连同。这种情况可以分为两种情况:(1)选中的两图案方块在同一直线,两折点间的直连线可在其这两个方块之间的空间位置作移动,其约束是不超过游戏边界区域。(2)选中的两图案方块不在同一直线,两折点间的直连线可在两个方块之间的空间位置作移动,其约束是两方块之间的区域。经过上面详细的分析后,可以对选定的两方块是否可以作抵消操作可以这样设计下去。首先,对简单的直接连情况进行判断,看其是否符合条件,假如不能,再加深一个级别的复杂度,对一个折点
17、的情况进行判断,依次类推,如下图所示。图 2.2第 12 页图 2.3根据如图 1.6 所示的流程图,可以对选定的两个方块(分别在(x1,y1)以及(x2,y2)两个区域位置,其中 x,y 分别代表行与列的概念)是否可以抵消作以下实现。把该功能封装在 Pass()函数里面,其代码如下所示:/ 判断选中的两个方块是否可以消除BOOL CPocketLianDlg:Pass(int x1, int y1, int x2, int y2)/消去图片/X 直连方式if(x1=x2)if(X1EqualX2(x1,y1,y2)return TRUE;/Y 直连方式else if(y1=y2)第 13 页
18、if(Y1EqualY2(x1,x2,y1)return TRUE;/一个拐点的联通方式if(OnePlumb(x1,y1,x2,y2)return TRUE;/两个拐点的联通方式else if(TwoPlumb(x1,y1,x2,y2)return TRUE;return FALSE;在上面的实现中,先是对直连方式中的 x 方向直连 Y1EqualY2()以及 y 方向直连 X1EqualX2()这两种情况进行判断,如果尚未取得结果,再通过调用OnePlumb()函数对一个折点的情况进行判断,或者更糟糕的时候调用TwoPlumb()函数对两个这点的情况进行判断,然后得出最终结果。下面将对上面
19、涉及到的子功能模块进行实现,代码如下所示:/x 直连通BOOL CPocketLianDlg:X1EqualX2(int x, int y1,int y2) /保证 y1 的值小于 y2if(y1y2)/数据交换int n=y1;y1=y2;y2=n;第 14 页/ 直通 for(int i=y1+1;i-1)break;/左通if(XThrough(x-1,y1,FALSE)/右通if(XThrough(x+1,y1,TRUE)return FALSE;/Y 直通BOOL CPocketLianDlg:Y1EqualY2(int x1,int x2,int y)/ 保证 x1 的值小于 x2
20、if(x1x2)/数据交换int x=x1;x1=x2;x2=x;/直通第 15 页for(int i=x1+1;i-1)break;/上通if(YThrough(x1,y-1,FALSE)/下通if(YThrough(x1,y+1,TRUE)return FALSE;/ 是否同一直线通BOOL CPocketLianDlg:LineX(int x,int y1,int y2)/if(y1y2)int y=y1;y1=y2;y2=y;for(int y=y1;y-1)return FALSE;第 16 页if(y=y2)return TRUE;return FALSE;/ 是否同一直线通BOO
21、L CPocketLianDlg:LineY(int x1,int x2,int y)if(x1x2)int x=x1;x1=x2;x2=x;for(int x=x1;x-1)return FALSE;if(x=x2)return TRUE;return FALSE;/一个拐点连通BOOL CPocketLianDlg:OnePlumb(int x1, int y1,int x2, int y2) if(x1x2)int n=x1;x1=x2;第 17 页x2=n;n=y1;y1=y2;y2=n;if(y2x2)int n=x1;x1=x2;第 18 页x2=n;n=y1;y1=y2;y2=n
22、;/右通if(XThrough(x1+1,y1,TRUE)/左通if(XThrough(x1-1,y1,FALSE)/上通if(YThrough(x1,y1-1,FALSE)/下通if(YThrough(x1,y1+1,TRUE)/右for(int x=x1+1;x-1)break;if(OnePlumb(x,y1,x2,y2)return TRUE;/左for(x=x1-1;x-1;x-)if(m_Playery1*m_nCol+x-1)第 19 页break;if(OnePlumb(x,y1,x2,y2)return TRUE;/上for(int y=y1-1;y-1;y-)if(m_Pl
23、ayery*m_nCol+x1-1)break;if(OnePlumb(x1,y,x2,y2)return TRUE;/下for(y=y1+1;y-1)break;if(OnePlumb(x1,y,x2,y2)return TRUE;return FALSE;这里把直接连接方式分为直通,左通,右通 3 种情况,如 1.7 图所示。下面简单介绍直通和左通两种情况(右通与左通类似)(1)直通:直通就是在选定的两个方块直连线中,没有被任何方块所阻碍。(2)左通:左通就是选定的两个方块的直连线之间有其他方块阻碍,但是通过它的左侧可以将它们无阻碍地连通。直连方式中的此种情况跟前面分析的第 20 页两个折
24、点连接方式中的其中一点相当类似,如 1.8 图所示。它们之间的区别就是,左通的连接线直接在其相邻的位置连通,从而不构成垂直折点的效果,而两个折点连同方式中的其中一个类似的情况是,线的连通起码要偏移一个方块的距离来形成连通。图 1.7 图 1.8同理,有上通和下通,它们的情况与左通和右通类似。2.4 游戏结束或死锁的判断要判断游戏的结束,只需对地图中的所有区域的状态进行检测就可以了,若检测到地图中所有的图片都被消除,则证明游戏结束。当区域中出现任意不可能消除的两个图片时,游戏进入死锁状态。/检测游戏是否结束BOOL CPocketLianDlg:IsWin(void)/检测所有是否尚有非未被消除
25、的方块for(int i=0;im_nRow*m_nCol;i+)if(m_mapi != BLANK_STATE)return FALSE;return TRUE;/死锁状态如下图所示:第 21 页3、系统的实现与调试3.1 调试过程程序调试过程中出现的错误信息如下:-Configuration: PocketLian - Win32 (WCE ARMV4I) Debug-Compiling resources.Compiling.PocketLian.cppStdAfx.cppLinking.uafxwced.lib(afxmem.obj) : error LNK2005: “void *
26、 _cdecl operator new(unsigned int)“ (?2YAPAXIZ) already defined in coredll.lib(COREDLL.dll)uafxwced.lib(afxmem.obj) : error LNK2005: “void _cdecl operator delete(void *)“ (?3YAXPAXZ) already defined in coredll.lib(COREDLL.dll)uafxwced.lib(afxmem.obj) : warning LNK4006: “void * _cdecl operator new(un
27、signed int)“ (?2YAPAXIZ) already defined in coredll.lib(COREDLL.dll); second definition ignoreduafxwced.lib(afxmem.obj) : warning LNK4006: “void _cdecl operator delete(void *)“ (?3YAXPAXZ) already defined in coredll.lib(COREDLL.dll); second definition ignoredCreating library ARMV4IDbg/PocketLian.lib
28、 and object ARMV4IDbg/PocketLian.expcorelibc.lib(pegwmain.obj) : error LNK2019: unresolved external symbol WinMain referenced in function WinMainCRTStartupARMV4IDbg/PocketLian.exe : fatal error LNK1120: 1 unresolved externalsError executing link.exe.PocketLian.exe - 4 error(s), 2 warning(s)解决方法如下:(1
29、)点击 project 目录下的 project Setting 进入相关页面后,选择Link,在下面的 Category 栏中选择 Input,然后将 object/library modules下的 commctrl.lib coredll.lib 及 Ignore libraries 下的$(CENoDefaultLib)删除第 22 页(2)将 Category 栏中类容选择为:Output ,然后将 Entry-point symbol 下的 Entry-point symbol 的内容改为:wWinmainCRTStartup 。经过以上两步的修改后,程序可以正常运行。3.2 系统运行的结果(1)初始界面(2) 运行时界面第 23 页(4) 游戏结束时界面第 24 页