蛇身:由数组构造
移动:绘制一个新蛇头,擦掉蛇尾,更新数组
进食:判断一旦蛇头遇到食物,则只增加蛇头而不擦除蛇尾,更新数组
1)用户通过w, s, a, d键控制蛇的上下左右移动(一次移动一个方格长度)
2)一般情况下界面保持有一个随机的食物,由“□”表示;即蛇每吃掉一个食物,再随机出现下一个食物;界面初始化时会给出一个食物
3)蛇的长度不能超过80;蛇不能碰壁; 否则游戏结束,显示最终得分
#include
#include
#include
#include
#include
#define MAX_LEN 80//the longest length for the snake
#define WIDETH 56
#define HIGHTH 30
int x, y;//coordinate for food, one at a time
int score = 0;
typedef struct {
int x;
int y;
} point;
struct {
int len = 3;
point arr[MAX_LEN];
point head;
} snake;
void gotoxy(int, int);
关于移动光标的函数,更详细的解释在这篇文章里:
代码实现:
void gotoxy(int x, int y) {
COORD coord = { x, y };
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}
边框可自己视情况设定;
初始的蛇设长度为3;
以实心方块打印边框和蛇;
void initialize();
代码实现:
void initialize() {
int i;
for (i = 0; i < WIDETH + 1; i++) {
printf("■");
}
gotoxy(0, HIGHTH);
for (i = 0; i < WIDETH + 1; i++) {
printf("■");
}
for (i = 0; i < HIGHTH + 1; i++) {
gotoxy(0, i);
printf("■");
}
for (i = 0; i < HIGHTH + 1; i++) {
gotoxy(WIDETH * 2, i);
printf("■");
}
gotoxy(WIDETH - 2, HIGHTH / 2);
snake.head = { WIDETH + 4, HIGHTH / 2 };//to print the tail first
for (i = 0; i < snake.len; i++) {
snake.arr[i] = { WIDETH - 2 + 2 * i , HIGHTH / 2 };
printf("■");
}
}
利用函数getch()从控制台读取一个字符,返回一个整数,方便给下一步的移动操作指令
(当然这一块是可以和move合并的)
int key();
代码实现:
int key() {
int ch, op;
ch = _getch();
switch ((char)ch) {
case 'w':op = 1;break;//up
case 's':op = 2;break;//down
case 'a':op = 3;break;//left
case 'd':op = 4;break;//right
default:op = 0;
}
return op;
}
找到新蛇头;
若 蛇头碰到了食物:
增加长度;增加分数;打印新蛇头
若 未碰到食物:
更新蛇身数组;打印新蛇头;擦除蛇尾
int move(int);
代码实现:
int move(int op) {
point new_head;
switch (op) {
case 1:new_head.x = snake.head.x; new_head.y = snake.head.y - 1; break;
case 2:new_head.x = snake.head.x; new_head.y = snake.head.y + 1; break;
case 3:new_head.x = snake.head.x - 2; new_head.y = snake.head.y; break;
case 4:new_head.x = snake.head.x + 2; new_head.y = snake.head.y; break;
}
if (new_head.x <= 0 || new_head.y <= 0) return -1;
if (new_head.x == x && new_head.y == y) {
snake.len++;
score++;
snake.arr[snake.len - 1] = { x, y };
snake.head = new_head;
gotoxy(x, y);
printf("■");
return 1;
}
else {
int i;
gotoxy(snake.arr[0].x, snake.arr[0].y);
printf(" ");//erasure the tail
gotoxy(new_head.x, new_head.y);
printf("■");
for (i = 1; i < snake.len; i++) {
snake.arr[i - 1] = snake.arr[i];
}
snake.arr[snake.len - 1] = new_head;
snake.head = new_head;
return 0;
}
}
注意:表示食物的方块在x轴(横坐标)占2个单位长度
void food();
代码实现:
void food() {
while (1) {
x = rand() % (WIDETH * 2 - 2) + 2;
if (x % 2 == 0) break;
}
y = rand() % (HIGHTH - 1) + 1;
gotoxy(x, y);
printf("□");
}
判断蛇身是否达到设定最长;
判断是否碰壁;
int judge();
代码实现:
int judge() {
if (snake.len >= MAX_LEN) return -1;
if (snake.head.x >= 112 || snake.head.y >= 30) {
return -1;
}
return 0;
}
思路:
初始准备;
循环{
一旦遇到输入,进行移动并判断,直到判断结果非法,游戏结束
}
int main() {
srand((unsigned)time(NULL));
initialize();
food();
while (1) {
if (_kbhit) {
int t = key();
if (t < 0) {
gotoxy(120, 32);
printf("Game Over1 : %d", score);
return 0;
}
int b = move(t);
if (b == 1) food();
if (judge() < 0) {
gotoxy(120, 32);
printf("Game Over2 : %d", score);
return 0;
}
}
}
return 0;
}
关于各个边界条件的判断分散在不同的地方(函数块),显得杂乱无章
很多细节有待完善,譬如
蛇的直接回头(蛇头方向调转180°)可以设为非法操作;
蛇不能碰到自己的身体;
增加暂停功能;
实时显示分数变化;
用户不进行操作时也让蛇保持移动,用户操作只改变蛇的加速度方向