# Snake **Repository Path**: xiaomingcai/Snake ## Basic Information - **Project Name**: Snake - **Description**: Visual C++ 实现的贪吃蛇游戏 - **Primary Language**: C++ - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-09-27 - **Last Updated**: 2021-09-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Snake Visual C++ 实现的贪吃蛇游戏 贪吃蛇是诺基亚手机中一个经典的休闲游戏。程序使用 Visual C++ 6.0,基于 MFC 编写,很好的还原了该游戏。 ## 一、项目名称: 贪吃蛇游戏 ## 二、功能描述: 类似于诺基亚经典的手机游戏“贪吃蛇”,即一条蛇在空间里移动,当吃到食物的时候,蛇身便会增加一节,如此下去,直到碰上墙壁或碰上自己的身体,游戏随即结束。 ## 三、算法设计与实验步骤 本程序主要包括四个核心算法。 1. 上下左右控制蛇身移动。蛇身移动的思想是,在每个时钟周期内,增加蛇头,删除蛇尾。 2. 随机产生一个食物,当产生的食物与蛇身重合时。重新产生一个。 3. 当蛇吃到食物时,蛇身长度增加,其思想是,增加蛇头,不删除蛇尾。 4. 蛇碰到墙,或自己的身体,即蛇头超出游戏区域,或者蛇头与蛇身重合时,结束游戏。 * 程序还包括音乐、音效的开关,蛇运动速度的设置。运动速度越高,每吃一个食物所产生的分数就越高。 * 当窗口失去焦点时,游戏自动暂停,重新获得焦点时,自动开始游戏。 * 四、类与对象结构描述,核心程序代码(需要有相应的注释) * 整个界面采用了单文档(SDI)形式。 * 蛇身采用CArray模板类。 * 食物采用CPoint类。 ## 四、类与对象结构描述,核心程序代码 * 整个界面采用了单文档(SDI)形式。 * 蛇身采用CArray模板类。 * 食物采用CPoint类。 ### 1. CSnakeCore类 程序的核心类。 // 上下左右 const int UP = 1; const int DOWN = 2; const int LEFT = 3; const int RIGHT = 4; class CSnakeCore { public: // 游戏区域 int x, y; // 左上角坐标 int width, height; // 宽度和高度,单位为方格 int pixel; // 每个方格的像素 int score; // 分数 int level; // 等级 bool isPause; // 游戏是否暂停 bool isOver; // 游戏是否结束 bool hasChanged; // 在一个周期内蛇的方向只能改变一次 int currentDirection; // 当前移动方向 CArray snakeBody; // 蛇身 CPoint food; // 食物 BOOL hasMusic; // 音乐 BOOL hasSound; // 音效 public: CSnakeCore(); // 构造函数 virtual ~CSnakeCore(); // 析构函数 public: void initSnake(); // 初始化函数 void createFood(); // 产生食物的函数 }; ### 2. CSnakeView类 主要的函数有: * OnDraw(CDC* pDC): 绘制游戏区域,界面。 * OnTimer(UINT nIDEvent): 计时器函数。注:因为编写的过程中不会处理类与类之间复杂的变量传递,为了简单,只能把更新蛇身、更新分数、碰撞检测、播放音效等等代码都放入了该函数,导致函数过于繁琐。此处还是有待于改进。 * OnGameStart(): 按下菜单【游戏 -> 开始】后,开始游戏。 * OnGameSet(): 按下菜单【游戏 -> 设置】后,设置游戏速度,音乐、音效等参数。 * OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags): 键盘响应。上下左右控制蛇身运动,空格暂停游戏。 * OnKillFocus(CWnd* pNewWnd): 当窗口失去焦点时,自动暂停游戏。 * OnSetFocus(CWnd* pOldWnd): 当窗口重新获得焦点时,自动继续游戏。 以下是OnTimer函数:由于代码过长,所以此处用伪代码表示。 void CSnakeView::OnTimer(UINT nIDEvent) { if (aSnake.isPause) { 暂停游戏 } else if (aSnake.isOver){ 结束计时器 if (aSnake.hasSound) { 播放游戏结束的音效 } 结束游戏 } else { 移动蛇头 碰撞检测 判断是否吃到食物 } CView::OnTimer(nIDEvent); } ### 3. CSnakeSetDlg类 游戏设置的模态对话框类。 ## 五、使用说明 依次点击 “游戏 -> 开始”,便会开始游戏,用键盘的上下键控制蛇的移动方向,空格键暂停或继续游戏。 依次点击“游戏 -> 设置…”,会出现设置菜单,如图2,可以设置蛇的移动速度和音乐音效的开关(移动速度越高,吃到食物所奖励的分值越高)。 ## 六、小结与思考 本程序构思于2009年12月4日,10日开始写代码,完成于16日,因为是第一次使用MFC写程序,所以其间遇到了很多很多的问题,通过参考相关的书籍,通过网络上的求助,最终得到解决。在此处声明:本程序除了参考了前辈们的一些优良的算法外,其他包括CSnakeCore类的设计,游戏界面设计,速度调节功能等均属原创。 程序设计的过程中,遇到无法解决的问题有: 1. 各个类之间成员函数的调用: 比如在CSnakeCore类中想写一个函数控制屏幕的输出,但不知道如何操作。 2. 程序还存在一个Bug,即在运行过程中,偶尔会出现程序停止响应,初步猜测是OnTimer()函数或是CArray类本身存在的一些问题。待解决。 3. 设置蛇身大小:原计划通过调节CSnakeCore类中pixel(像素)变量的值来该面蛇身的大小,但是为了程序稳定性,禁用了改功能。 通过以上的问题,发现自己在C++方面的功底还是比较薄弱,对于MFC的原理,以及MFC的API的关系,思路还不是很清晰,准备在这个假期内,搞明白。 同时,已解决的问题有: 1. 设计初期,如果键盘在一个时钟周期内连续按键多次,则会造成错误的方向而使得程序意外结束。因此在按键响应函数中添加了一个标志hasChanged,使得蛇的移动方向在一个时钟周期内只能改变一个,从而避免了这个Bug。 2. 将蛇的移动速度和控件的值相关联。起初不明白如何将CSnakeView中定义的CSnakeCore的对象的属性值传入Slider控件和Check Box控件,最后发现在CSnakeView中定义对话框类的一个对象,可以直接赋值。 3. 在PreCreateWindow()中设置了窗口的一些风格,例如禁用了最大化按钮,禁止调节窗口大小,居中窗口等。 4. 使用状态栏显示当前游戏的一些信息,如速度、分数、状态(暂停或结束)。 为了提高游戏的可玩性,还计划在游戏加入一些奖励方法,例如每吃到十个食物便会出现一个分值很高的大食物;也可以加入一些障碍物。当然,这都需要更好的MFC功底,并要继续深入地学习。