MFC实现贪吃蛇游戏之游戏窗口

来源:互联网 发布:java 防止恶意刷短信 编辑:程序博客网 时间:2024/05/16 08:05
贪吃蛇大家肯定都玩过,这里我就暂时不给出做好的DEMO了,我们一起来一步一步实现贪吃蛇

在此之前一定要说明的是,这是基于MFC的贪吃蛇,所以你必须的掌握MFC和C++的基础(后期会出一个基于C语言控制台的),其次,里面的代码一定要自己练习,掌握,复制粘贴是学不会的!

我们这里实现的只是一些基本的功能,如果大家想添加一些比如关卡,分数金钱等等可以完成之后自行添加,不懂的可以来提问,我们会尽量帮大家解决。
如果大家觉得有什么不妥的地方或者有什么疑问可以向我说


首先我们拿VS建立一个MFC的工程,工程名叫Snake,选择对话框工程。(这一步不会的,可以先去看MFC基础教程了)

工程建好后,我们会得到这样的对话框
我们把上面的控件全部删了,然后规划下游戏窗口区域
上图中,我画了一个绿色的框框,绿色框框里面,表示是游戏区域。也就是蛇运动的区域,当蛇碰到这个绿色边框,或者出了边框,游戏就结束,就得重新来过。

也就是说,我们得在对话框上画一个边框出来,为了好看,最好在里面加上别的颜色,比如,把对话框涂黑,然后画一条绿色边框
比如像这个样子
这个图是我用微软自带的画图工具画的)
好的,既然我们有了目标,那我们来简单的规划下,
首先,我们得有办法把窗口涂黑,我们知道,在对话框重绘的时候 会调用OnPaint,那就是说,我们只有在OnPaint里面调对应的画图函数,就能把窗口涂黑了,
然后,窗口不能盲目的涂黑,我们得在边框留成绿色,让玩家知道 什么时候是要出边界了,
所以,我们得窗口应该得改成这样子

[C] 纯文本查看 复制代码
?
1
2
3
4
5
6
111111111111111
100000000000001
100000000000001
100000000000001
100000000000001
111111111111111

我们把上面的一串数字想象成我们的窗口,1表示边框,0表示游戏区域,也就是说,我们只要能把窗口和上面的数字对应起来,我们就能按数字的内容给软件染色,这就简单了,我们可以定义一个二维数据,把它初始化成上面那样

既然有了思路,那我们开始写代码吧~
首先我们打开SnakeDlg.cpp(如果你们的工程名不叫Snake的话,就不叫这个名字,比如你的工程叫dbgpro的话,文件就叫dbgproDlg.cpp)
我们找到OnPaint函数,OnPaint函数代码如下

[C++] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
voidCSnakeDlg::OnPaint()
{
        if(IsIconic())
        {
               CPaintDC dc(this);// 用于绘制的设备上下文
                SendMessage(WM_ICONERASEBKGND,reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
                // 使图标在工作区矩形中居中
                intcxIcon = GetSystemMetrics(SM_CXICON);
                intcyIcon = GetSystemMetrics(SM_CYICON);
                CRect rect;
                GetClientRect(&rect);
                intx = (rect.Width() - cxIcon + 1) / 2;
                inty = (rect.Height() - cyIcon + 1) / 2;
                // 绘制图标
                dc.DrawIcon(x, y, m_hIcon);
        }
        else
        {
               CDialogEx::OnPaint();
        }
}

我们把里面的代码全部删了,只留下 CPaintDC dc(this); 和CDialogEx::OnPaint();

当然,这一步不是必要了,只是为了代码更少,我们看起来方便,如果你懒得删的话,把我们要添加代码写到esle分支就行了
精简后的代码如下

[C++] 纯文本查看 复制代码
?
1
2
3
4
5
6
voidCSnakeDlg::OnPaint()
{
        CPaintDC dc(this);
// 用于绘制的设备上下文
       CDialogEx::OnPaint();
}

我们先去头文件,定义一个int数组

private:
int m_arrGameRange[18][20];
这里,我们定义了一个18行,20列的数组来表示游戏区域,当然,在实际项目中,这种“魔数”最好用宏定义,比较方便改,我们这里也改成宏好了
数组定义好以后,我们定义一个初始化函数,专门用来初始化游戏的数据,void InitGameData();因为这个函数不会在外部调用,我把它设为私有函数好了,
那么,我们根据上面的那一堆数字来思考下,我们要怎么初始化数据
http://www.bcwhy.com/thread-27688-1-1.html
111111111111111
100000000000001
100000000000001
100000000000001
100000000000001
111111111111111
我们看到第1行(下标是0)和最后一行(下标是GAME_ROW-1)

第1列(下标是0)和最后一列(下标是GAME_COL-1)
要设置1,其他的是0,那么代码如下
[C++] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
voidCSnakeDlg::InitGameData()
{
        for(inti=0; i<GAME_COL; i++)
        {
                for(intj=0; j<GAME_ROW;j++)
                {
                        if((i==0||i==GAME_COL-1)||(j==0||j==GAME_ROW-1))
                        {
                                m_arrGameRange[i][j = 1;
                        }
                        else
                        {
                                m_arrGameRange[i][j = 0;
                        }
                }
        }
}


我们知道,对话框创建好了调用的第一个函数是OnInitDialog(),我们在OnInitDialog()函数的return之前调用我们得初始化函数,
MFC实现贪吃蛇游戏之游戏窗口
然后调试看看对不对
结果是对的,现在我们就在对话框重绘的时候,也就是OnPaint来调用画图的函数,把颜色涂上去,
我们先把对话框涂黑,然后再涂边框
编写后 OnPaint的代码如下

[C++] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
voidCSnakeDlg::OnPaint()
{
        CPaintDC dc(this);// 用于绘制的设备上下文
        CBrush brushGame(RGB(255,255,255));//创建黑色画刷 用来画游戏区域
        CBrush brushBorder(RGB(34,176,76));//创建绿色画刷 用来画边框
        //遍历行、列来画不同的颜色
        for(inti = 0; i < GAME_COL; i++)
        {
                for(intj = 0; j < GAME_ROW; j++)
               {
                        //根据行列来计算一个矩形大小,每个矩形占20个像素
                        CRect rt;
                        rt.left = i*20;
                        rt.top = j*20;
                        rt.right = rt.left + 20;
                        rt.bottom = rt.top + 20;
                        if(m_arrGameRange[i][j == 1)//需要画边框
                       {
                                dc.SelectObject(brushBorder);//把我们得画刷选入DC
                                dc.Rectangle(rt);//填充矩形,参数表示要填充的矩形区域
                        }
                        else
                        {
                                dc.SelectObject(brushGame);//把我们得画刷选入DC
                                dc.Rectangle(rt);//填充矩形,参数表示要填充的矩形区域
                        }
                }
        }
        CDialogEx::OnPaint();
}

效果如下
我们发现,我们画的列太少了,得加几个(哈哈, 定义成宏的优势出来了),然后每个格子有黑线,
我们先把列的宏改大点。我改成28刚刚好
#define GAME_COL 28 //游戏区域的列
每个格子有黑线,是因为我们用的Rectangle这个函数画的,它帮我们画了边框,我是为了方便调试,故意用的它现在我们把红酒的颜色换成黑色,然后顺便把黑框框去掉,去掉黑框框简单,只要把
dc.SelectObject(brushBorder);//把我们得画刷选入DC
dc.Rectangle(rt);//填充矩形,参数表示要填充的矩形区域
换成dc.FillRect(rt, &brushGame);
最终的代码如下

[C++] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
voidCSnakeDlg::OnPaint()
{
        CPaintDC dc(this);// 用于绘制的设备上下文
        CBrush brushGame(RGB(0,0,0));//创建黑色画刷 用来画游戏区域
        CBrush brushBorder(RGB(34,176,76));//创建绿色画刷 用来画边框
        //遍历行、列来画不同的颜色
        for(inti = 0; i < GAME_COL; i++)
        {
                for(intj = 0; j < GAME_ROW; j++)
                {
                        //根据行列来计算一个矩形大小,每个矩形占20个像素
                        CRect rt;
                        rt.left = i*20;
                        rt.top = j*20;
                        rt.right = rt.left + 20;
                        rt.bottom = rt.top + 20;
                        if(m_arrGameRange[i][j == 1)//需要画边框
                        {
                                //填充矩形的函数,
                                //第一个参数是要填充的矩形
                                //第二个参数是什么什么画刷填充矩形
                               dc.FillRect(rt, &brushBorder);
                       }
                        else
                        {
                               dc.FillRect(rt, &brushGame);
                        }
                }
        }
        CDialogEx::OnPaint();
}

最终效果如下
好了,今天就到这里,下次我们要在这条代码上实现一条蛇~
MFC实现贪吃蛇游戏之游戏窗口
1 0