致阅卷人:请直接跳至“新·贪吃蛇”部分
在作业发布的两个月前,我提前知道了将会有贪吃蛇作业。所以当时熬夜攻关,写出了一个贪吃蛇。然而到等到作业正式发布的时候,我惊讶地发现,我的代码完全不能过关……
元·贪吃蛇
原本的贪吃蛇由于想使用队列来模拟一条蛇,所以使用了C++的STL库。
将游戏的本体单独制作成一个类,主函数负责处理用户输入与系统输出,另外有一个控制蛇自动前进的模块。
本体
一个完整的贪吃蛇游戏有以下组件:
1. 场景
2. 蛇
3. 水果
对于游戏中的任意一个方块,它的状态只有以下几种:
1. 空闲的方块
2. 被蛇的身体占用
3. 被水果占用
4. 是墙
这就方便了我们使用一个枚举类型来表示方块的状态:
typedef enum BLOCK_STATUS {
spare,
wall,
snake,
fruit
} blockStatus;
另外,由于蛇需要自动运动,必须要存储一个变量来记录蛇的运动方向。于是我又创建了一个枚举类型来表示方向:
typedef enum SNAKE_FACING {
snake_up,
snake_down,
snake_left,
snake_right
} snake_facing;
贪吃蛇很重要的部分是蛇的运动。蛇在每一次运动时候都需要对它前方的方块进行特别处理。
大体思路为:
1. 获取蛇尾的方块的指针
2. 将蛇尾的状态设置为“空闲”,即蛇尾先收缩
3. 根据蛇的面朝方向,调整蛇头的xy坐标
4. 根据蛇头的新xy坐标,获取相对应的方块指针
5. 根据新蛇头所在方块的状态,分以下情况:
* 墙和蛇身体:游戏结束,调用postGameOver()处理善后事宜
* 水果:蛇的尾部方块状态重新变成“蛇身”;将蛇头加入队列;将蛇头的方块状态设置为“蛇身”;如果全部方块都被蛇占据,则游戏胜出,否则重新放置水果
* 空闲:将蛇头方块状态设置为“蛇身”;将蛇头加入队列;蛇尾离开队列
根据这样的思路,可以写出如下代码:
void snakeStage::moveSnake(void) {
blockStatus *freedBlock = snake_body.front();
changeBlockStatus(freedBlock, spare);
blockStatus *nextBlock;
switch (currentFacing) {
case snake_up:
snake_head_y--;