MFC实现贪吃蛇游戏之蛇的移动

来源:互联网 发布:sql嵌套循环语句 编辑:程序博客网 时间:2024/05/16 08:21
本来这个文章周日准备更新的,但是有点别的事,就推迟了一天~
给文章下方增加了打赏功能,大家要是喜欢我们的文章的话可以打赏我们,也可以通过微信公众号或者本站留言,给我们建议和意见!3Q
http://www.bcwhy.com/thread-27783-1-1.html
通过上两次的文章,我们已经能把游戏框框和蛇给画出来了,现在我们要做的就是,移动我们的蛇,老规矩,我们先来整理下思路,我们蛇是存在链表里面的,链表的每个节点就是蛇的身体的每一节,所谓移动,就是算一下蛇头的位置,然后蛇身体往上一节点移动,第一节身体的值等于蛇头,第二节身体的值等于第一节身体…………然后再重绘下,看起来就像是再移动了,然后我们需要的是,没过一段时间,就要让蛇移动一下,这样就看起来像是在动,然后,键盘按W S A D分别上 下 左 右 移动,

我们来看下面这张图, 左边是我们认为的蛇头,右边是蛇尾,我们定义两个指针,分别指向蛇的最后一个元素,和倒数第二个元素,分别是BODY和HEAD,我们用Head的值来覆盖BODY的值,然后把body和head分别往前移动一个节点,之所以不从前往后覆盖是因为 当你第一个元素的值覆盖了第二个元素,再用第二个元素覆盖第三个元素的时候,其实是拿第一个元素的值去覆盖的~
上面两个图思路理清楚了,我们就可以开始写代码了~

我们先在头文件 定义一个枚举
[C++] 纯文本查看 复制代码
?
1
2
3
4
5
6
7
enumMOVEENUM
{
        LEFT,
        RIGHT,
        UP,
        DOWN,
};
用来表示当前蛇朝那个方向移动,然后定义一个成员变量
MOVEENUM m_snakeMove;
在构造函数给他初始化成向左移动,代码如下
[C++] 纯文本查看 复制代码
?
1
2
3
4
5
6
CSnakeDlg::CSnakeDlg(CWnd* pParent /*=NULL*/)
        : CDialogEx(IDD_SNAKE_DIALOG, pParent)
        , m_snakeMove(LEFT)//默认向左移动
{
        m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
我们只加了, m_snakeMove(LEFT)//默认向左移动这已经,好了 继续下一步

上面说了,需要蛇看起来像自己在动,那么,我们就需要一个定时器,不停的算蛇的位置,我们先定义一个定时器,加在InitGameData()里面,我们用SetTimer来设置一个定时器,这个API有3个参数
MSDN的解释如下
nIDEvent
指定一个非零计时器标识符。 如果计时器标识符是唯一的,则此相同的值将由 SetTimer 返回。 否则,
SetTimer 确定一个新的唯一值并返回它。 针对窗口计时器(具备 NULL 回调功能),该值必须仅对与当前窗口相关的窗口计时器是唯一的。 针对回调计时器,该值对于全部过程中的所有计时器必须是唯一的。 因此,创建回调计时器时,很有可能返回的值不同于您指定的值。
nElapse
指定超时值或间隔(以毫秒为单位)。
lpfnTimer
指定应用程序提供的 TimerProc 处理 WM_TIMER 消息的回调函数的地址。 如果此参数为 NULL, WM_TIMER
消息将置于应用程序的消息队列中,并由 CWnd
对象处理。

第一个参数是一个定时器ID,我们照样在头文件定义一个宏,方便以后使用和修改
#define BEGINGAME 1000 //定时器宏,控制蛇移动的
然后

SetTimer(BEGINGAME, 500, NULL);
这样调用这个API,我们希望500毫秒刷新一次,回调函数我们传的NULL,我们只要响应WM_TIME消息 就能处理定时器回调了,
我们切换到类视图,然后找到我们的对话框类,点右键->类向导
添加好WM_TIMER消息以后,我们代码里面会多一个OnTimer函数
我们把代码改成
[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
32
33
34
35
36
37
38
voidCSnakeDlg::OnTimer(UINT_PTRnIDEvent)
{
        if(nIDEvent == BEGINGAME)
        {
                list<SNAKE>::iterator itHead = m_listSnake.end();
                list<SNAKE>::iterator itBody = m_listSnake.end();
                itBody--;
                itHead--;
 
                while(itHead != m_listSnake.begin())
                {
                        itHead--;
                        itBody->nCol = itHead->nCol;
                        itBody->nRow = itHead->nRow;
                        itBody--;
                }
                itHead = m_listSnake.begin();
                switch(m_snakeMove)
                {
                caseLEFT:
                        itHead->nCol -= 1;
                        break;
                caseRIGHT:
                        itHead->nCol += 1;
                        break;
                caseUP:
                        itHead->nRow -= 1;
                        break;
                caseDOWN:
                        itHead->nRow += 1;
                        break;
                }
 
                Invalidate();
        }
 
        CDialogEx::OnTimer(nIDEvent);
}
http://www.dbgpro.com/archives/322.html
Invalidate();是系统API 用来强制重绘当前窗口的,因为我们在OnPaint里面画的蛇,所以只有重绘,蛇就动了
上面的while循环,就是我们之前所说的从后往前遍历,赋值的循环
我们运行起来看看 蛇是不是会动了
蛇已经会动了,只会往左边走(因为我们初值是往左边走),再加个键盘控制移动,今天的任务就算完成了~
我们按刚才添加WM_TIMER消息的步骤来添加一个WM_KEYDOWN消息, 添加好了以后 会多一个void CSnakeDlg::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)函数
我们在OnKeyDwon里面添加如下代码
[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
32
33
34
voidCSnakeDlg::OnKeyDown(UINTnChar, UINTnRepCnt, UINTnFlags)
{
        switch(nChar)
        {
        case'W':
                if(m_snakeMove != DOWN)
                {
                        m_snakeMove = UP;
                }
                break;
        case'S':
                if(m_snakeMove != UP)
                {
                        m_snakeMove = DOWN;
                }
                break;
        case'A':
                if(m_snakeMove != RIGHT)
                {
                        m_snakeMove = LEFT;
                }
                break;
        case'D':
                if(m_snakeMove != LEFT)
                {
                        m_snakeMove = RIGHT;
                }
                break;
        default:
                break;
        }
 
        CDialogEx::OnKeyDown(nChar, nRepCnt, nFlags);
}
Char是表示哪个键被按下了,这里我们判断WSAD,如果按下了,W,我们就上移动,但是 上移动之前,我们要判断之前是不是下移动,之前已经在往下走,就不能往上走,要不然蛇头会画在蛇身上~


MFC实现贪吃蛇游戏之蛇的移动
0 1
原创粉丝点击