Jiahonzheng's Blog

字符游戏-贪吃蛇

字数统计: 998阅读时长: 3 min
2017/12/25 Share

贪吃蛇)是一个产生于 1970 年代中后期的计算机游戏,在 1990 年代由于一些小屏幕设备引入而再度流行起来。相信大家对这款经典的游戏一定不陌生。

在本篇博文中,笔者将实现字符版本的贪吃蛇。

游戏代码:Greedy-Snake

运行环境:Windows (后期会加入 Mac、Linux 支持)

游戏需求分析

在游戏设计之前,我们首先要回忆贪吃蛇的游戏过程和细节:

  • 系统生成位置随机的食物
  • 蛇只能进行上、下、左、右四个方向的移动
  • 蛇在吃到食物后,其长度增加
  • 在蛇头碰到墙壁或者自己的身体时,结束游戏

游戏设计方案

在回忆贪吃蛇游戏的基本游戏过程和相关细节之后,我们需要根据这些需求制定一个可行的游戏设计方案,这里采用的是自顶向下、逐步求精的设计方法。

欲了解更多有关“自顶向下、逐步求精”的知识,可以点击此处跳转到我的另一篇博客。

自顶而下

有了前面的游戏需求分析,我们即可将游戏分为三大过程:

  • 初始化阶段
  • 运行阶段
  • 结束阶段

上述通过自顶而下设计的三个阶段,也是总控函数 main 的三个运行阶段。

逐步求精

在设计的“逐步求精”阶段,我们需要对模块进行不断地细化。

初始化阶段

  • 定义相关字符图形
1
2
3
4
5
#define SNAKE_HEAD 'H'
#define SNAKE_BODY 'X'
#define BLANK_CELL ' '
#define WALL_CELL '*'
#define FOOD '$'
  • 定义和初始化相关变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// bulid and initialize the map
char map[13][13] = {
"************",
"*XXXXH *",
"* *",
"* *",
"* *",
"* *",
"* *",
"* *",
"* *",
"* *",
"* *",
"************",
};

// initialize the x-coordinate of each cell of the snake
int snakeX[SNAKE_MAX_LENGTH] = { 1, 2, 3, 4, 5 };

// initialize the y-coordinate of each cell of the snake
int snakeY[SNAKE_MAX_LENGTH] = { 1, 1, 1, 1, 1 };

// initialize the length of the snake
int snakeLength = 5;

// initialize the x-coordinate of the food
int foodX = 0;
int foodY = 0;

运行阶段

  • 生成位置随机的食物
1
2
// create the food on a randomized blank cell
void createFood(void);
  • 控制蛇的运动
1
2
3
4
5
// snakeMove(dx, dy)
// snake stepping:
// dx = -1(left), 1(right), 0(no move);
// dy = -1(up), 1(down), 0(no move)
void snakeMove(int, int);
  • 判断是否吃到食物
1
2
3
4
// check whether the snake eats the food:
// yes >>> return 1;
// no >>> return 0
int checkSnakeEatFood(void);
  • 判断是否结束游戏
1
2
3
4
// check whether the snake head touches the body or wall:
// yes >>> return 1;
// no >>> return 0
int checkSnakeDie(void);

结束阶段

  • 结束提示
1
2
// outs when gameover
void gameover(void);

游戏具体实现

游戏数据结构与算法

在实现贪吃蛇的运动时,我们需要选择一种合适的数据结构。在查阅相关资料,我们有两个候选项:数组和链表。为了让游戏实现更为简明,笔者采用数组的方式,当然从性能上考虑,链表更为优秀,后续我会在 Github 上给出两种存储方式的游戏实现。

我们发现,我们可以把蛇移动一格的过程理解为把头部增加一格、尾部减少一格,通过这种方式(算法),应该可以实现最少的操作次数。

具体代码

由于篇幅的原因,具体代码可以点击此处跳转查看。

游戏效果

游戏创新玩法

游戏暂停与恢复机制

为了提升用户的游戏体验,在游戏实现中,笔者加入了手动暂停(P)、恢复游戏(C)和退出(Q)功能。

游戏不足

由于时间的关系(笔者最近在忙着小程序外包),笔者在制作游戏时,没有使用无阻塞输入和定点光标输入的方法,所以在游戏运行时,需要(自动)刷新控制台并绘制地图,在这个过程会造成屏幕的闪烁,给用户带来了不好的体验,后续在 Github 上,笔者会不断对游戏进行更新优化,敬请谅解。

CATALOG
  1. 1. 游戏需求分析
  2. 2. 游戏设计方案
    1. 2.1. 自顶而下
    2. 2.2. 逐步求精
      1. 2.2.1. 初始化阶段
      2. 2.2.2. 运行阶段
      3. 2.2.3. 结束阶段
  3. 3. 游戏具体实现
    1. 3.1. 游戏数据结构与算法
    2. 3.2. 具体代码
    3. 3.3. 游戏效果
  4. 4. 游戏创新玩法
    1. 4.1. 游戏暂停与恢复机制
  5. 5. 游戏不足