小球游戏
MFC课程设计说明书
设计题目: 彩蛋游戏(消除类小游戏)
所属系部: 计算机工程系
专 业: 计算机科学与技术
一、 设计任务
1.1 任务描述
使用MFC在工作区内随机出现一定数目的小球,其中有空的地方,按照一定的规则可以消去屏幕中的小球,若正确消除,则可以得分。整个游戏有时间限制。
1.2 设计要求
- 在游戏开始前显示欢迎画面。。
- 能够在屏幕中显示游戏区,并可以用鼠标控制游戏进行小球的消除。
- 使用定时器控制游戏的时间,游戏时间到则游戏结束并弹出对话框提醒。。
- 每次用户消去小球则显示用户的得分。
- 屏蔽MFC的主框架,并在工作区中自绘按钮,且有按下时的效果。自绘按钮包括“开始”、“暂停”、“帮助”。
- 当用户点击暂停按钮的时候将所有颜色的小球全部变灰,并且暂停时间。
- 当用户点击开始按钮的时候将所有参数恢复默认,使游戏重新开始。
- 本游戏的窗口大小不可变。
1.3 效果图
设计效果图及游戏图见附页。
图1 小球碰撞效果图
二、 设计思路
2.1游戏设计思路
本设计首首先利用数组存放15*25的分别从0~5的随机数,再利用函数根据不同的随机数在屏幕上画出不同颜色的小球(其中值为0的位置默认为空图形)。在用户点击屏幕中空图形的地方,判断其四个方向的小球是否相同,如果相同则将其消除(值变为0),并将增加积分。
2.2自绘按钮思路
以开始按钮为例。整个按钮效果分为两幅图(效果1、效果2)。在不同的情况下调用。首先在窗口可以看到的地方绘制效果1按钮,在工作区外面再绘制效果2按钮。当用户点击按钮位置(LButtonDown)的时候把工作区外面的效果2按钮绘制到效果1的位置,在LButtonUp里面恢复效果2按钮的默认位置实现了自绘按钮。
2.3游戏时间控制条的设计思路
在右上方导入位图,其长度储存在参数length里面。在定时器里面对此长度进行控制。在
pDC->BitBlt(30,2,length,27,&MemDC,0,0,SRCCOPY);
之中控制需要显示的部分从而达到控制时间的目的。在长度小于一定值的时候弹出对话框提示用户。
三、 关键源代码及注释
3.1 变量及函数。
变量及函数
1 public:
2 virtual ~CWorkView();
3 BOOL start;//开始
4 BOOL m_bpause;//暂停
5 CBitmap ball1;
6 CBitmap ball2;
7 CBitmap ball3;
8 CBitmap ball4;
9 CBitmap ball5;
10 CBitmap ball1a;
11 CBitmap ball2a;
12 CBitmap ball3a;
13 CBitmap ball4a;
14 CBitmap ball5a;
15 CBitmap ballblack;
16 CBitmap startbutton;
17 CBitmap startbutton2;//自绘按钮资源
18 CBitmap pausebutton;
19 CBitmap pausebutton2;
20 CBitmap helpbutton;
21 CBitmap helpbutton2;
22 CBitmap startpage;//欢迎画面
23 CBitmap countdown;//计时条
24 int length;//计时条长度
25 int starty;//控制自绘按钮效果2位置变化
26 int pausey;
27 int helpy;
28 bool checking;//判断是否有小球消除
29
30
31 int x1,y1;//储存鼠标点击位置上下左右四个小球的位置便于比较
32 int x2,y2;
33 int x3,y3;
34 int x4,y4;
35 int score;//积分
36
37 int positionx,positiony;//将鼠标位置转化为游戏数组的下标位置.
38 int Game[100][100];//游戏数组
39 void CWorkView::DrawBall(CDC* pDC);//画小球
40 void CWorkView::ColorBall(CDC* PDC,int m,int n);//根据不同数组位置不同的值确定要画的小球的颜色
41 void CWorkView::GrayBall(CDC* pDC,int m,int n);
42 void CWorkView::DrawButton(CDC* pDC);//自绘按钮的绘制
43 void CWorkView::DrawBkg(CDC* pDC);//背景的绘制
44 void CWorkView::OnStart();//开始的控制,包括将所有参数恢复默认值
45 void CWorkView::DrawScore(CDC* pDC);//在右上角画出时间
46 void CWorkView::Check(int,int,int,int,int,int,int,int);//判断是否需要消除,并指定checking的bool值
47 void CWorkView::GetPosition(int,int);//获取鼠标点击位置上下左右四个小球的位置
3.2 开始函数
利用随机数分别给数组里面每个数都赋值。
1 void CWorkView::OnStart()
2 {
3 srand((unsigned)time(NULL));
4 for(int m=1;m<26;m++)
5 {
6 for(int n=1;n<16;n++)
7 {
8 Game[m][n]=rand()%6;
9 }
10 }
11 length=394;
12 }
3.3 画积分函数
积分
1 void CWorkView::DrawScore(CDC* pDC)
2 {
3 int nOldDC=pDC->SaveDC(); //设置字体
4 CFont font;
5 if(0==font.CreatePointFont(200,"隶书"))
6 {
7 AfxMessageBox("Can't Create Font");
8 }
9 pDC->SelectObject(&font);//设置字体颜色及其背景颜色
10 CString str;
11 pDC->SetTextColor(RGB(128,0,128));
12 pDC->SetBkMode(TRANSPARENT);//文字透明
13 str.Format("%d",score);
14 if(score>=0)
15 pDC->TextOut(720,5,str);
16
17 pDC->TextOut(630,5,"得分:");
18
19 pDC->RestoreDC(nOldDC);
20
21 }
22
3.4 重置球体位置函数
自绘按钮
1 void CWorkView::DrawButton(CDC* pDC)
2 {
3 CDC dc;CBitmap* pOldBitmap;
4 CDC MemDC;
5 MemDC.CreateCompatibleDC(&dc);;
6 pOldBitmap=MemDC.SelectObject(&startbutton);
7 pDC->BitBlt(680,480,780,485,&MemDC,0,0,SRCCOPY);
8
9 pOldBitmap=MemDC.SelectObject(&startbutton2);
10 pDC->BitBlt(680,starty,780,485,&MemDC,0,0,SRCCOPY);
11
12 pOldBitmap=MemDC.SelectObject(&pausebutton);
13 pDC->BitBlt(570,480,670,485,&MemDC,0,0,SRCCOPY);
14
15 pOldBitmap=MemDC.SelectObject(&pausebutton2);
16 pDC->BitBlt(570,pausey,670,485,&MemDC,0,0,SRCCOPY);
17
18 pOldBitmap=MemDC.SelectObject(&helpbutton);
19 pDC->BitBlt(460,480,560,485,&MemDC,0,0,SRCCOPY);
20
21 pOldBitmap=MemDC.SelectObject(&helpbutton2);
22 pDC->BitBlt(460,helpy,560,485,&MemDC,0,0,SRCCOPY);
23 }
3.5 根据数组的值来画小球
彩球
1 void CWorkView::ColorBall(CDC* pDC,int m,int n)
2 {
3 CDC dc;CBitmap* pOldBitmap;
4 CDC MemDC;
5 MemDC.CreateCompatibleDC(&dc);
6
7 switch(Game[m][n])
8 {
9 case 1:
10 {
11 pOldBitmap=MemDC.SelectObject(&ball1a);
12 pDC->BitBlt(m*30,n*30,m*30+30,m*30+30,&MemDC,0,0,SRCCOPY);
13
14 break;
15 }
16 case 2:
17 {
18 pOldBitmap=MemDC.SelectObject(&ball2a);
19 pDC->BitBlt(m*30,n*30,m*30+30,m*30+30,&MemDC,0,0,SRCCOPY);
20
21 break;
22 }
23 case 3:
24 {
25 pOldBitmap=MemDC.SelectObject(&ball3a);
26 pDC->BitBlt(m*30,n*30,m*30+30,m*30+30,&MemDC,0,0,SRCCOPY);
27 break;
28 }
29 case 4:
30 {
31 pOldBitmap=MemDC.SelectObject(&ball4a);
32 pDC->BitBlt(m*30,n*30,m*30+30,m*30+30,&MemDC,0,0,SRCCOPY);
33 break;
34 }
35 case 5:
36 {
37 pOldBitmap=MemDC.SelectObject(&ball5a);
38 pDC->BitBlt(m*30,n*30,m*30+30,m*30+30,&MemDC,0,0,SRCCOPY);
39 break;
40 }
41 default:
42 {
43 break;
44 }
45 }
46 }
3.6获取当前鼠标点击位置上下左右四个方向最近的小球数组下标位置
获取要消除小球的位置
1 void CWorkView::GetPosition(int positionx,int positiony)
2 {
3
4 if(Game[positionx][positiony]==0)
5 {
6 for(int m=positionx+1;m<26;m++)//Right
7 {
8 if(Game[m][positiony]!=0)
9 {
10 x1=m;y1=positiony;
11 break;
12 }
13 }
14
15 for(int n=positionx-1;n>0;n--)//Left
16 {
17 if(Game[n][positiony]!=0)
18 {
19 x2=n;y2=positiony;
20 break;
21 }
22 }
23
24 for(int p=positiony-1;p>0;p--)//Up
25 {
26 if(Game[positionx][p]!=0)
27 {
28 x3=positionx;y3=p;
29 break;
30 }
31 }
32 for(int q=positiony+1;q<16;q++)//Down
33 {
34 if(Game[positionx][q]!=0)
35 {
36 x4=positionx;y4=q;
37 break;
38 }
39 }
40 }
41 }
3.7
判断要消除的小球
1 void CWorkView::Check(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4)
2 {
3 int a=Game[x1][y1];
4 int b=Game[x2][y2];
5 int c=Game[x3][y3];
6 int d=Game[x4][y4];
7 if(b==a)
8 {
9 Game[x2][y2]=0;Game[x1][y1]=0;score++;checking=true;
10 }
11 if(c==a)
12 {
13 Game[x3][y3]=0;Game[x1][y1]=0;score++;checking=true;
14 }
15 if(d==a)
16 {
17 Game[x4][y4]=0;Game[x1][y1]=0;score++;checking=true;
18 }
19 if(c==b)
20 {
21 Game[x3][y3]=0;Game[x2][y2]=0;score++;checking=true;
22 }
23 if(d==b)
24 {
25 Game[x4][y4]=0;Game[x2][y2]=0;score++;checking=true;
26 }
27 if(d==c)
28 {
29 Game[x4][y4]=0;Game[x3][y3]=0;score++;checking=true;
30 }
31
32
33 }
3.8鼠标按下时的响应消息
此部分包括:1,自绘按钮在这部分生效。2,负责更新窗口的个个部分。3,消除按游戏要求的小球。
代码
1 void CWorkView::OnLButtonDown(UINT nFlags, CPoint point)
2 {
3 // TODO: Add your message handler code here and/or call default
4
5 if(point.y>480&&point.y<505&&point.x>680&&point.x<780)//开始按钮
6 {
7 OnStart();
8 start=TRUE;
9 SetTimer(1,200,NULL);
10 score=0;
11 starty=starty-30;
12 }
13
14 if(point.y>480&&point.y<505&&point.x>570&&point.x<670)//暂停按钮
15 {
16
17 m_bpause=!m_bpause;
18 if(m_bpause==FALSE)
19 {
20 SetTimer(1,200,NULL);
21 length=length+30;
22 }
23 pausey=pausey-30;
24 if(m_bpause==TRUE)
25 {
26 KillTimer(1);
27 }
28
29 }
30 if(point.y>480&&point.y<505&&point.x>460&&point.x<560)//帮助按钮
31 {
32 helpy=helpy-30;
33 CMyDlg dlg;
34 dlg.DoModal();//调用帮助对话框
35 }
36 positionx=point.x/30;//获得鼠标点击位置对应的数组下标
37 positiony=point.y/30;
38 GetPosition(positionx,positiony);//以参数传递,获得位置
39 if(start==true&&m_bpause==false){
40 if(Game[positionx][positiony]==0)
41 {
42 checking=false;
43 Check(x1,y1,x2,y2,x3,y3,x4,y4);//判断是否需要消除,如果有可以消除则会返回checking=true;
44 }
45 if(checking==false)
46 length=length-30;//如果用户点击出错则减短用户的游戏时间
47 //以下代码表示只刷新屏幕中特定的位置!
48 CRect ballup(x1*30,y1*30,x1*30+30,y1*30+30);
49 InvalidateRect(&ballup);
50
51 CRect balldown(x2*30,y2*30,x2*30+30,y2*30+30);
52 InvalidateRect(&balldown);
53
54 CRect ballright(x3*30,y3*30,x3*30+30,y3*30+30);
55 InvalidateRect(&ballright);
56
57 CRect ballleft(x4*30,y4*30,x4*30+30,y4*30+30);
58 InvalidateRect(&ballleft);
59
60 CRect scoreboard(630,0,750,30);
61 InvalidateRect(&scoreboard);
62 }//开始才执行的
63 CRect button(460,480,780,510);
64 InvalidateRect(&button);
65 CView::OnLButtonDown(nFlags, point);
66 }
3.9鼠标按下时的函数
此部分复位按钮的效果2
鼠标起来
1 void CWorkView::OnLButtonUp(UINT nFlags, CPoint point)
2 {
3 // TODO: Add your message handler code here and/or call default
4 if(point.y>480&&point.y<505&&point.x>680&&point.x<780)
5 {
6 starty=510;Invalidate();
7 }
8 else if(point.y>480&&point.y<505&&point.x>570&&point.x<670)
9 {
10 pausey=510;Invalidate();
11 }
12 if(point.y>480&&point.y<505&&point.x>460&&point.x<560)
13 {
14 helpy=510;
15 }
16 CView::OnLButtonUp(nFlags, point);
17 }
3.10
此部分负责调用各个部分的函数和时间控制条。
Ondraw
1 void CWorkView::OnDraw(CDC* pDC)
2 {
3
4 CWorkDoc* pDoc = GetDocument();
5 ASSERT_VALID(pDoc);
6 CRect rcClient;
7 GetClientRect(rcClient);
8 CDC dc;
9 CBitmap MemBitmap;
10 CDC MemDC;
11 MemDC.CreateCompatibleDC(&dc);
12 CBitmap *pOldBitmap = MemDC.SelectObject(&MemBitmap);
13
14 if(start==FALSE)
15 {
16 pDC->FillSolidRect(rcClient,RGB(255,255,255));
17 MemDC.SelectObject(&startpage);
18 pDC->BitBlt(30,30,750,450,&MemDC,0,0,SRCCOPY);
19 }
20 else if(start==TRUE)
21 {
22 DrawBkg(pDC);//背景
23 MemDC.SelectObject(&countdown); //时间控制条
24 pDC->BitBlt(30,2,length,27,&MemDC,0,0,SRCCOPY);
25
26 }
27 DrawScore(pDC);//积分
28
29 if(m_bpause==TRUE)
30 {
31 for(int m=1;m<26;m=m+1)
32 {
33 for(int n=1;n<16;n=n+1)
34 {
35 if(Game[m][n]!=0)
36 {
37 pOldBitmap=MemDC.SelectObject(&ballblack);
38 pDC->BitBlt(m*30,n*30,m*30+30,m*30+30,&MemDC,0,0,SRCCOPY); //暂停的时候把所有的小球都变为黑色以免游戏作弊。
39 }
40 }
41
42 }//*/
43 }
44 else
45 {
46
47 }
48
49
50 if(m_bpause==FALSE)
51 {
52 DrawBall(pDC);//画小球
53 }
54
55 DrawButton(pDC);//画按钮
56
57 MemDC.DeleteDC();
58 MemBitmap.DeleteObject();
59 // TODO: add draw code for native data here
60 }
四、 总结
4.1 设计方案拓展
设计一个最高分机制,在游戏结束后要求用户输入自己的名字,将用户所有玩的最高的10个积分利用文档序列保存到文件中,在游戏中可以调用。
添加小球消除后的动画,现在是小球直接消除,不够直观,不能给用户良好的游戏体验。
4.2 目前存在的问题
由于没有全部使用双缓冲而是利用其他函数而使屏幕没有严重的闪屏,现在的程序虽然不影响游戏但是还是有轻微的闪屏。这个问题会在将来的改进中予以改正。
五、 参考文献
《深入浅出MFC》
《VC++应用教程》
posted on 2010-12-18 20:49 NigelOnTheWeb 阅读(749) 评论(0) 收藏 举报
浙公网安备 33010602011771号