贪吃蛇详解Windows编程(一)

来源:互联网 发布:java连接zookeeper报错 编辑:程序博客网 时间:2024/06/06 18:49

贪吃蛇可以用很多种语言写,但是基本的思路都是一样的,在这里我就用C/C++写,但不是纯C或者纯C++写,因为那样太没效率了,用Windows封装的API写会节省很多代码而且是有界面的。既然是详解,所以一篇文章肯定讲不完的,所以我会分开几篇讲。

一个小建议:如果只有C或C++基础而没学过Windows程序设计,那么只建议看看思路即可,如果简单的学过一些Windows可以看完全篇.

先说一下思路,不管做什么东西首先都先要有整体的大概布局以及思路,然后再一小步一小步的去完成,去堆积,到后面就完成了。
(建议看了思路有想法的先去自己写,实在不会再看效果会加倍。)
思路如下:
1.画游戏区和控制区
也许有人会问为什么要分两个区域,理由很简单啊,难道你想程序已运行就自动开始,然后没有暂停按钮没有加速按钮没有减速按钮没有分数显示吗?当然了也可以全部设置成键盘快捷键控制,但是那样有些人就不太会用,导致这个游戏只能你自己玩。

2.画出蛇身
区域画出来了,第二部当然先要去画蛇了,千万别一步登天的想马上让蛇动起来,那样你会很困难,新手就基本就不能完成了。画蛇身的时候只要随便给它几节就行,因为程序都是由特殊性到一般性。

3.让蛇动起来
蛇身画出来后就可以让它动了,我估计很多人包括我都在怎么让蛇身动起来这里卡住了,方法各种各样,但就是千万别用Sleep函数。在这里我们用SetTimer函数设置一个定时器,每隔多少ms就移动一次蛇身(这里我用整体移动而不是一节节移动,就是隔多少ms重画一次蛇身)这里的间隔就是速度了。

4.制作食物
既然蛇都动起来了,那肯定要有食物给它吃吧?先别管吃了食物蛇会干嘛,我们就只管制作食物先,这就是物理的分离法分析,各个部分独立出来分析,然后最后再合并。

5.让蛇吃食物
这里只是判断蛇吃到食物没有,还没让它增加长度

6.吃食物后让蛇身增长
这里只需要调用第5个步骤判断,然后让它是否增长就行

下面这些都是控制区的了,控制区可以随意设置,并无什么技术含量,只是一些个性化。
7.开始和暂停按钮

8.蛇的速度按钮

9.游戏等级

10时间计时

11.分数显示


我会采用片段讲解,最后会贴出全部代码,如果没兴趣看片段详解可以跳到最后一篇文章直接看全部代码。
实战讲解:

1.画游戏区和控制区
首先游戏区和控制区是相互独立的区域,所以要有边界宽度来分割它们,然后游戏区和控制区和父窗口之间也要有分隔,这样整体感才强。
代码片段如下:

//游戏区和控制区宽度高度,这里*10是蛇的Size,后面会懂的。#define  GAME_WIDE         70        //游戏区宽度70*10#define  GAME_HEIGHT       60       //游戏区高度60*10#define  CTRL_WIDE         30       //控制区宽度30*10#define  CTRL_HEIGHT       60        //控制区高度60*10#define  BOUNDSIZE         10       //边界厚度10   //[其它代码]static int  ixWind = 0, iyWind = 0;//窗口大小参数static int ixClient = 0, iyClient = 0;//客户区大小参数//[其它代码]case WM_CREATE:       {         //获取窗口大小           GetWindowRect(hWnd, &rect);            ixWind = rect.right - rect.left;            iyWind = rect.bottom - rect.top;         //获取客户区大小            GetClientRect(hWnd, &rect);            ixClient= rect.right - rect.left;            iyClient= rect.bottom - rect.top;         //修改窗口大小            int nWideth = BOUNDSIZE * 3 + (GAME_WIDE + CTRL_WIDE)*SNAKESIZE + (ixWind - ixClient);            int nHeight = BOUNDSIZE * 2 + GAME_HEIGHT*SNAKESIZE + (iyWind - iyClient);            MoveWindow(hWnd, 50, 50,nWideth ,nHeight ,TRUE);    }               break;[其它代码] case WM_PAINT:        {            PAINTSTRUCT ps;            HDC hdc = BeginPaint(hWnd, &ps);            //游戏区画刷            static HBRUSH hBrush1 = CreateSolidBrush(RGB(58, 206, 66));            //控制区画刷            static HBRUSH hBrush2 = CreateSolidBrush(RGB(80, 87, 196));            //画游戏区            Rectangle(hdc, BOUNDSIZE, BOUNDSIZE, BOUNDSIZE+GAME_WIDE*SNAKESIZE,            BOUNDSIZE+GAME_HEIGHT*SNAKESIZE);            //填充游戏区颜色            SetRect(&rect, BOUNDSIZE, BOUNDSIZE, BOUNDSIZE + GAME_WIDE*SNAKESIZE,                BOUNDSIZE + GAME_HEIGHT*SNAKESIZE);            FillRect(hdc, &rect,hBrush1);            //画控制区            Rectangle(hdc, BOUNDSIZE * 2 + GAME_WIDE*SNAKESIZE, BOUNDSIZE,                BOUNDSIZE*2+(GAME_WIDE+CTRL_WIDE)*SNAKESIZE, BOUNDSIZE+CTRL_HEIGHT*SNAKESIZE);            //填充控制区颜色            SetRect(&rect, BOUNDSIZE * 2 + GAME_WIDE*SNAKESIZE, BOUNDSIZE,                 BOUNDSIZE * 2 + (GAME_WIDE + CTRL_WIDE)*SNAKESIZE,                BOUNDSIZE + CTRL_HEIGHT*SNAKESIZE);            FillRect(hdc, &rect,hBrush2);            EndPaint(hWnd, &ps);        }        break;

也许有人会问为什么可以在case里面定义变量,因为你在case到break;之间加了一对大括号,学过C的都知道块作用域吧?道理就是那样。里面的一些x,y坐标和宽度高度,你自己算一下就可以懂了,如果你懒的话,你就OVER了。
效果如图:

2.画出蛇身
画蛇身之前还要初始化蛇身
初始化要在WM_CREATE消息中初始化.
画蛇要在WM_PAINT消息中调用
代码片段如下:

#include<vector>//蛇的信息#define   SNAKESIZE      10     //蛇的宽高都为10的小方块#define   SNAKEMAX       100     //蛇身长度最大值为100std::vector<POINT> vSnakePoint;//声明蛇的坐标UCHAR ucSnakeHead = 4;//初始化蛇头为4,实际上是vSnakePoint[3];UCHAR ucSnakeTail = 0;//初始化蛇尾为0UCHAR ucSnakekLen = 4;//初始化蛇身长度为4[其它代码]//初始化蛇VOID InitSnake(){    //先清空坐标    vSnakePoint.clear();    //给蛇坐标分配空间    vSnakePoint.resize(SNAKEMAX);    //游戏结束后再次初始化    ucSnakeHead = 4;//初始化蛇头为4,实际上是vSnakePoint[3];    ucSnakeTail = 0;//初始化蛇尾为0    ucSnakekLen = 4;//初始化蛇身长度为4    //初始化每一节的蛇身坐标    for (int i = 0;i < ucSnakekLen;i++)    {        vSnakePoint[i].x = i;        vSnakePoint[i].y = 0;    }}//画蛇身,hdc是在WM_PAINT消息中传进来的,所以画蛇要在那里调用这个函数VOID DrawSnake(HDC hdc){   //蛇的颜色画刷    static HBRUSH hBrush = CreateSolidBrush(RGB(0,243,222));    SelectObject(hdc, hBrush);    //画蛇    for (int i = 0;i < ucSnakekLen;i++)    {        Rectangle(hdc, vSnakePoint[i].x*SNAKESIZE+BOUNDSIZE, vSnakePoint[i].y*SNAKESIZE+BOUNDSIZE,            (vSnakePoint[i].x+1)*SNAKESIZE + BOUNDSIZE, (vSnakePoint[i].y+1)*SNAKESIZE + BOUNDSIZE);    }}

千万不要看到这些长长的宏定义就怕,其实它们就是一个常数而已,你们都可以自己动手算算的,如果封装成类的话就不会有那么多宏定义出现在函数里了。
效果如图:

区域和蛇身都画完了,下一篇就讲解如何移动它!

0 0
原创粉丝点击