课 程 设 计
设计题目 扫雷游戏程序设计 学生姓名
学 号 专业班级 指导教师
2013 年 11 月 5 日
合肥工业大学课程设计任务书
设计题目 扫雷游戏程序设计 成绩 扫雷游戏是Windows操作系统自带的一款小游戏,在过去的几年里Windows操作系统历经数次换代更新,变得越来越庞大、复杂,功能也越来越强大,但是这款小游戏依然保持原来的容貌,可见这款小游戏受到越来越多人的喜爱。 课 程 设 计 主 要 内 容 参考系统自带的扫雷程序,自行开发设计一款扫雷游戏。 要求: (1)鼠标左击排雷,右击插小旗,打问号; (2)方格里面的数字表示方格周围的雷数; (3)能够显示未标记雷数和游戏用时; (4)雷区上面的小脸可以变化,显示微笑,惊讶,痛苦,胜利。在任何情况下单击小脸可以重新开始游戏; (5)可进行游戏难度的设定:包括预定义的难度级别(雷区行数,列数和雷数),和自行定义雷区行数,列数和雷数的功能; (6)排行榜功能,扫雷成功时候,根据游戏用时更新排行榜。 建议:从学生的工作态度、工作量、设计(论文)的创造性、学术性、实用性及书面表达能力等方面给出评价。 指 导 教 师 评 语 签名: 200 年 月 日
一. 设计任务
(1)鼠标左击排雷,右击插小旗,打问号; (2)方格里面的数字表示方格周围的雷数; (3)能够显示未标记雷数和游戏用时;
(4)雷区上面的小脸可以变化,显示微笑,惊讶,痛苦,胜利。在任何情况下单击小脸可以重新开始游戏;
(5)可进行游戏难度的设定:包括预定义的难度级别(雷区行数,列数和雷数),和自行定义雷区行数,列数和雷数的功能;
(6)排行榜功能,扫雷成功时候,根据游戏用时更新排行榜。
二. 具体设计
(一)、设计思路
扫雷游戏是很经典也很有趣的一款游戏,这次的游戏程序设计要求设计出功能与原游戏相近的一款游戏,首先定义变量和类要画出游戏方格以及位图,设计游戏等级,等级越高方格越多雷数也越多;然后设置随机布雷以保证每次重新开始游戏都有不同的雷区地图;另外定义鼠标左击扫雷,左击标记周围埋雷情况,右击奇数次排雷偶数次取消上次排雷,以及扫雷第一次左击不能扫到雷。
(二)、设计表示:
类名 CMyView 成员类别 属性 类型 int int int int int int int int short CBitmap CBitmap Lei 方法 afx_msg void afx_msg void afx_msg void afx_msg void afx_msg void afx_msg void afx_msg void afx_msg void afx_msg int Lei 属性 int int leftnum leinum n jieshu realnum secondstart m_RowCount m_ColCount second m_Bitmap[12] m_anniu[4] lei[50][50] OnTimer(UINT nIDEvent) OnLButtonDown(UINT, CPoint) OnStart() OnLButtonUp(UINT, CPoint ) OnRButtonDown(UINT, CPoint) OnEasy() OnMiddle() OnHard() OnCreate(LPCREATESTRUCT) weitu shumu 成员名 剩下雷数 雷数 定义格数 结束 真实雷数 开始计时 行 列 计时 位图数组 按钮数组 最大雷区 计时器函数 左键按下消息 开始函数 左键抬起消息 右键按下消息 简单模式函数 中等模式函数 困难模式函数 创建窗口函数 标志位图 标志状态 描述 (三)、实现功能 1、鼠标左击排雷,右击插小旗,打问号; 2、方格里面的数字表示方格周围的雷数; 3、能够显示未标记雷数和游戏用时;
4、雷区上面的小脸可以变化,显示微笑,惊讶,痛苦,胜利。在任何情况下单击小脸可以重新开始游戏;
5、可进行游戏难度的设定:包括预定义的难度级别(雷区行数,列数和雷数); 6、任何时候开始游戏第一次点击不会扫到雷。
由于时间等原因未完成功能:
排行榜和自行定义雷区行数,列数和雷数功能。 (四)、详细设计 1、添加位图
前十二幅是在雷区的,后四幅是按钮。为了便于加载,必须各自保证其连续性。分别表示游戏进行的状态、结果胜利或触雷。
2、预设等级方格数雷数变化
void CMywqq20112074View::OnEasy() /////////////////////////////初级
{
m_RowCount=10;//行数10 m_ColCount=10;//列数10 leinum=10; realnum=leinum; SetTimer(1,50,NULL); // TODO: Add your command handler code here
second=0;//计时 secondstart=0;//1时开始计时 // num=0;
leftnum=leinum;//剩余雷数 jieshu=0;//jieshu=1时停止 int aa=0; //初始化0 for(int i=0;i j=0;j CMywqq20112074View::OnMiddle() //////////////////////////////////中级 { m_RowCount=15;//行数15 m_ColCount=15;//列数15 leinum=40; realnum=leinum; SetTimer(1,50,NULL); // TODO: Add your command handler code here second=0;//计时 secondstart=0;//1时开始计时 // num=0; leftnum=leinum;//剩余雷数 jieshu=0;//jieshu=1时停止 int aa=0; //初始化0 for(int i=0;i void CMywqq20112074View::OnHard() ///////////////////////////////////////////高级 { m_RowCount=25;//行数25 m_ColCount=16;//列数16 leinum=80; realnum=leinum; SetTimer(1,50,NULL); // TODO: Add your command handler code here second=0;//计时 secondstart=0;//1时开始计时 // num=0; leftnum=leinum;//剩余雷数 jieshu=0;//jieshu=1时停止 int aa=0; //初始化0 for(int i=0;i int k=rand()%m_RowCount; int l=rand()%m_ColCount; if(lei[k][l].shumu!=-1) { lei[k][l].shumu=-1; aa++; } }while(aa!=leinum); 3、 第一次点击不会扫到雷 if(lei[a][b].weitu==0||lei[a][b].weitu==3 ) { for(;n==0&&lei[a][b].shumu==-1;) //////////////踩到第一个雷 { int aa=0; //初始化0 for(int i=0;i lei[a][b].shumu++; } } 4、鼠标右击插小旗,打问号 第一次用右键单击某个区域时,该区域上插上一面小红旗,此时单击左键没有任何变化,第二次用右键单击时恢复原状。 //判断显示什么位图 //weitu=1已按下的数字区 //weitu=2显示旗 //weitu=3显示问号 for(int a=0;a { Dc.SelectObject(m_Bitmap[lei[a][b].shumu]); pDC->BitBlt(a*15+10,b*15+50,160,160,&Dc,0,0,SRCCOPY); } if(lei[a][b].weitu==2) { Dc.SelectObject(m_Bitmap[9]); pDC->BitBlt(a*15+10,b*15+50,160,160,&Dc,0,0,SRCCOPY); } if(lei[a][b].weitu==3) { Dc.SelectObject(m_Bitmap[10]); pDC->BitBlt(a*15+10,b*15+50,160,160,&Dc,0,0,SRCCOPY); } //结束 经运行测试之后,程序出现的问题有: 1、第一次打开游戏时有时会出现不能计时的情况 2、胜利的表情不能正常显示 (六)、使用说明 A、 鼠标左击排雷,右击插小旗,打问号; B、 方格里面的数字表示方格周围的雷数; C、 在任何情况下单击小脸可以重新开始游戏; 行定义雷区行数,列数和雷数的功能; E、 扫雷成功时候,游戏用时更新排行榜 (七)、运行实例 鼠标左击排雷,可翻开连片空格,方格周围数字表示周围埋雷数目,右键单击一次插小红旗,双击显示问号表示雷数情况未知,同时显示剩余雷数以及游戏用时 D、 可进行游戏难度的设定:包括预定义的难度级别(雷区行数,列数和雷数),和自 可从预设难度等级中选择游戏难度,游戏方格数和雷数都有相应增加 ←初级 ←中级 ←高级 触雷时现出痛苦的表情,游戏结束 将雷全部排出,胜利的呐喊!! (八)、设计小结 这个短短几天的C++课程设计虽然为期不长,却让我们从实践中学到了更多的C++编程知识,一开始看到示例中让人眼花缭乱的程序代码让人很有放弃的冲动,可是最后还是坚持下来将代码读完并自己琢磨出一套代码出来,在这中间也遇到不少的困难,一开始 不知道位图是怎么做的,那些看起来可爱的表情做起来却并不简单,还要在代码里将这些表情的二维坐标对应起来,过程细致而繁杂,最终在与同学讨论之后成功做出,大家还一起开玩笑涂鸦自定义表情,轻松的话语冲淡了写代码时的烦躁。还有在设定难度时要重新画方格,右键单击时出现不同的状态,第一次点击的时候不能扫到雷等等难关,都被坚持不懈的毅力和耐力一一克服。直到最后看到各种功能在自己手下实现,这时的成就感和喜悦是之前单独实现一个个小功能所不能比的,不由更加感叹程序编程的奇妙,让我对程序员有了新的认识,也下定决心努力向他们看齐!! 附录:源程序 // wqq20112074View.cpp : implementation of the CMywqq20112074View class // #include \"stdafx.h\" #include \"wqq20112074.h\" #include \"wqq20112074Doc.h\" #include \"wqq20112074View.h\" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CMywqq20112074View IMPLEMENT_DYNCREATE(CMywqq20112074View, CView) BEGIN_MESSAGE_MAP(CMywqq20112074View, CView) //{{AFX_MSG_MAP(CMywqq20112074View ) ON_WM_TIMER() ON_WM_LBUTTONDOWN() ON_WM_CREATE() ON_COMMAND(ID_START, OnStart) ON_WM_LBUTTONUP() ON_WM_RBUTTONDOWN() ON_COMMAND(ID_EASY, OnEasy) ON_COMMAND(ID_MIDDLE, OnMiddle) ON_COMMAND(ID_HARD, OnHard) //}}AFX_MSG_MAP // Standard printing commands ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIE W, CView::OnFilePrintPreview) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CMywqq20112074View construction/destruction CMywqq20112074View::CMywqq20112074View() { // TODO: add construction code here for(int ii=0;ii<16;ii++) m_Bitmap[ii].LoadBitmap(IDB_BITMAP14+ii); for(int jj=0;jj<4;jj++) m_anniu[jj].LoadBitmap(IDB_ANNIU1+jj); second=0;//计时 secondstart=0;//1时开始计时 m_RowCount=25;//行数 m_ColCount=16;//列数 n=0;//格数 leinum=5; realnum=leinum; leftnum=leinum;//剩余雷数 jieshu=0;//jieshu=1时停止 int aa=0; //初始化0 for(int i=0;i } //获取当前时间 CTime time=GetCurrentTime(); int s; //获取秒数 s=time.GetSecond(); //设置40个雷 do { //以当前秒数为产生随机算法 int k=(rand()*s)%m_RowCount; int l=(rand()*s)%m_ColCount; if(lei[k][l].shumu!=-1) { lei[k][l].shumu=-1; aa++; } }while(aa!=leinum); //给方格赋值,计算雷数 for(int a=0;a if(lei[c][d].shumu==-1) lei[a][b].shumu++; } } CMywqq20112074View::~CMywqq20112074View() { } BOOL CMywqq20112074View::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs return CView::PreCreateWindow(cs); } ///////////////////////////////////////////////////////////////////////////// // CMywqq20112074View drawing void CMywqq20112074View::OnDraw(CDC* pDC) { CMywqq20112074Doc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here //画背景 CBrush mybrush1; mybrush1.CreateSolidBrush(RGB(192,192,192 )); CRect myrect1(0,0,1200,800); pDC->FillRect(myrect1,&mybrush1); //画黑框 CBrush mybrush; mybrush.CreateSolidBrush(RGB(0,0,0)); CRect myrect(20,10,70,40); pDC->FillRect(myrect,&mybrush); CRect myrect2(325,10,375,40); pDC->FillRect(myrect2,&mybrush); CPen mypen; CPen*myoldPen; mypen.CreatePen(PS_SOLID,2,RGB(255,255,255)); myoldPen=pDC->SelectObject(&mypen); //画黑框的白线 pDC->MoveTo(20,40); pDC->LineTo(70,40); pDC->LineTo(70,10); pDC->MoveTo(325,40); pDC->LineTo(375,40); pDC->LineTo(375,10); //画雷区边线 for(int i=0;i } pDC->SelectObject(myoldPen); CPen mypen2; CPen*myoldPen2; mypen2.CreatePen(PS_SOLID,1,RGB(0,0,0)); myoldPen2=pDC->SelectObject(&mypen2); for(int ii=0;ii pDC->LineTo(10+ii*15+14,50+jj*15+14); pDC->LineTo(10+ii*15+14,50+jj*15); } pDC->SelectObject(myoldPen2); CDC Dc; if(Dc.CreateCompatibleDC(pDC)==FALSE) AfxMessageBox(\"Can't create DC\"); //显示按钮 Dc.SelectObject(m_anniu[0]); pDC->BitBlt(180,10,160,160,&Dc,0,0,SRCCOPY); //判断显示什么位图 //weitu=1已按下的数字区 //weitu=2显示旗 //weitu=3显示问号 for(int a=0;a Dc.SelectObject(m_Bitmap[lei[a][b].shumu]); pDC->BitBlt(a*15+10,b*15+50,160,160,&Dc,0,0,SRCCOPY); } if(lei[a][b].weitu==2) { Dc.SelectObject(m_Bitmap[9]); pDC->BitBlt(a*15+10,b*15+50,160,160,&Dc, 0,0,SRCCOPY); } if(lei[a][b].weitu==3) { Dc.SelectObject(m_Bitmap[10]); pDC->BitBlt(a*15+10,b*15+50,160,160,&Dc, 0,0,SRCCOPY); } //结束 if(jieshu==1&&lei[a][b].shumu==-1) { Dc.SelectObject(m_Bitmap[11]); pDC->BitBlt(a*15+10,b*15+50,160,160,&Dc, 0,0,SRCCOPY); Dc.SelectObject(m_anniu[3]); pDC->BitBlt(180,10,160,160,&Dc,0,0,SRCCO PY); } } //显示黑框里的数字 int nOldDC=pDC->SaveDC(); pDC->SetTextColor(RGB(255,0,0)); pDC->SetBkColor(RGB(0,0,0)); CFont font; if(0==font.CreatePointFont(160,\"Comic Sans MS\")) { AfxMessageBox(\"Can't Create Font\"); } pDC->SelectObject(&font); CString str; if(leftnum<10) str.Format(\"00%d\ else str.Format(\"0%d\ pDC->TextOut(25,10,str); if(second<10) str.Format(\"00%d\ else if(second<100) str.Format(\"0%d\" ,second); else str.Format(\"%d\" ,second); pDC->TextOut(330,10,str); pDC->RestoreDC(nOldDC); ////////////////////////////////////////////// } ///////////////////////////////////////////////////////////////////////////// // CMywqq20112074View printing BOOL CMywqq20112074View::OnPreparePrinting(CPrintInfo* pInfo) { // default preparation return DoPreparePrinting(pInfo); } void CMywqq20112074View::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add extra initialization before printing } void CMywqq20112074View::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add cleanup after printing } //////////////////////////////////////////////////////////////////////////// / // CMywqq20112074View diagnostics #ifdef _DEBUG void CMywqq20112074View::AssertValid() const { CView::AssertValid(); } void CMywqq20112074View::Dump(CDumpContext& dc) const { CView::Dump(dc); } CMywqq20112074Doc* CMywqq20112074View::GetDocument() // non-debug version is inline { ASSERT(m_pDocument->IsKindOf(RUNTIM E_CLASS(CMywqq20112074Doc))); return (CMywqq20112074Doc*)m_pDocument; } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CMywqq20112074View message handlers void CMywqq20112074View::OnTimer(UINT nIDEvent) { // TODO: Add your message handler code here and/or call default //结束,返回 if(jieshu==1) return; //显示个数为0的方格 leizero(); //计时 if(secondstart>0) secondstart++; if(secondstart==20) { secondstart=1; second++; //重画时间 CRect rect3; rect3.left=325; rect3.right=375; rect3.top=10; rect3.bottom=40; InvalidateRect(&rect3); } CView::OnTimer(nIDEvent); } void CMywqq20112074View::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default //获取指针pdc CDC *pDC=GetDC(); CDC Dc; if(Dc.CreateCompatibleDC(pDC)==FALSE) AfxMessageBox(\"Can't create DC\"); //显示按下按钮 if(point.x>180&&point.x<210&&point.y>10&&point.y<40) { Dc.SelectObject(m_anniu[3]); pDC->BitBlt(180,10,160,160,&Dc,0,0,SRCCO PY); } if((point.x>=10)&&(point.x<=385)&&(point.y>=50)&&(point.y<=290)) { if(jieshu==1) return; //显示张口按钮 Dc.SelectObject(m_anniu[1]); pDC->BitBlt(180,10,160,160,&Dc,0,0,SRCCO PY); secondstart=1; int a=(point.x-10)/15; int b=(point.y-50)/15; if(lei[a][b].weitu==0||lei[a][b].weitu==3) { for(;n==0&&lei[a][b].shumu==-1;) //////////////踩到第一个雷 { int aa=0; //初始化0 for(int i=0;i j=0;j lei[i][j].weitu=0; } } do { int k=rand()%m_RowCount; int l=rand()%m_ColCount; if(lei[k][l].shumu!=-1) { lei[k][l].shumu=-1; aa++; } }while(aa!=leinum); //给方格赋值 for(int
Copyright © 2019- azee.cn 版权所有 赣ICP备2024042794号-5
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务