C语言学习必须实战,并且学完语法后就必须立即用实战来巩固。一般需要10来个比较复杂的程序才能掌握C语言。今天就教大家第一个小程序,贪食蛇。
首先上代码
一、代码
#include <stdio.h>
#include <stdlib.h>
#include <curses.h>
#include <unistd.h>
#include <time.h>
#define WIDTH 20
#define HEIGHT 10
int score = 0;
int gameover;
int x, y, fruitX, fruitY, flag;
int tailX[100], tailY[100];
int nTail;
void setup() {
gameover = 0;
// 初始化蛇的位置
x = WIDTH / 2;
y = HEIGHT / 2;
// 初始化食物的位置
fruitX = rand() % WIDTH;
fruitY = rand() % HEIGHT;
}
void draw() {
clear(); // 清屏
for (int i = 0; i < WIDTH + 2; i++)
printw("#");
printw("\n");
for (int i = 0; i < HEIGHT; i++) {
for (int j = 0; j < WIDTH; j++) {
if (j == 0)
printw("#"); // 左墙
if (i == y && j == x)
printw("O"); // 蛇头
else if (i == fruitY && j == fruitX)
printw("F"); // 食物
else {
int isTail = 0;
for (int k = 0; k < nTail; k++) {
if (tailX[k] == j && tailY[k] == i) {
printw("o"); // 蛇身
isTail = 1;
}
}
if (!isTail)
printw(" ");
}
if (j == WIDTH - 1)
printw("#"); // 右墙
}
printw("\n");
}
for (int i = 0; i < WIDTH + 2; i++)
printw("#");
printw("\n");
printw("Score:%d", score);
refresh(); // 刷新屏幕
}
void input() {
int ch = getch(); // 获取键盘输入
switch (ch) {
case 'a':
flag = 1;
break;
case 'd':
flag = 2;
break;
case 'w':
flag = 3;
break;
case 's':
flag = 4;
break;
case 'x':
gameover = 1;
break;
}
}
void algorithm() {
usleep(100000); // 休眠,控制蛇的速度
int prevX = tailX[0];
int prevY = tailY[0];
int prev2X, prev2Y;
tailX[0] = x;
tailY[0] = y;
for (int i = 1; i < nTail; i++) {
prev2X = tailX[i];
prev2Y = tailY[i];
tailX[i] = prevX;
tailY[i] = prevY;
prevX = prev2X;
prevY = prev2Y;
}
switch (flag) {
case 1:
x--;
break;
case 2:
x++;
break;
case 3:
y--;
break;
case 4:
y++;
break;
default:
break;
}
// 判断是否碰到墙
if (x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT)
gameover = 1;
// 判断是否吃到食物
if (x == fruitX && y == fruitY) {
score += 10;
fruitX = rand() % WIDTH;
fruitY = rand() % HEIGHT;
nTail++;
}
}
int main() {
srand(time(NULL)); // 设置随机数种子
initscr(); // 初始化 curses
keypad(stdscr, TRUE); // 启用键盘输入
nodelay(stdscr, TRUE); // 非阻塞输入
noecho(); // 关闭回显
setup();
while (!gameover) {
draw();
input();
algorithm();
}
endwin(); // 关闭 curses
return 0;
}
二、编译
代码的运行平台是ubuntu,代码用到了curses库,需要提前安装:
sudo apt-get install libncurses5-dev
然后用下面命令编译
gcc snake_game.c -o snake_game -lncurses
执行程序:
./snake_game
注意!如果速度过快,就会结束,直接跳出程序到控制台,如何修改速度下面会讲到。
三、编程指导
-
初始化 (
setup
函数):gameover
: 游戏结束标志。x
和y
: 蛇头的初始坐标。fruitX
和fruitY
: 食物的初始坐标。flag
: 用于存储用户输入的方向。score
: 记录游戏得分。nTail
: 蛇身的长度。tailX
和tailY
: 用于存储蛇身各部分的坐标。
-
游戏主循环:
while (!gameover) { draw(); input(); algorithm(); }
游戏在一个无限循环中进行,直到
gameover
变为真。在每次循环中,先绘制游戏画面,然后处理用户输入,最后执行游戏逻辑。 -
输入处理 (
input
函数):- 使用
getch
函数获取键盘输入。 - 根据用户输入的键值设置
flag
的值,表示蛇移动的方向。 - 'a': 左,'d': 右,'w': 上,'s': 下,'x': 退出游戏。
- 使用
-
游戏逻辑 (
algorithm
函数):- 使用
usleep
函数添加一点延迟,以控制蛇的速度。(如果速度过快,游戏会很快结束,需要添加延时) - 更新蛇身的位置。
- 根据用户输入的方向移动蛇头。
- 判断是否碰到墙,如果是则游戏结束。
- 判断是否吃到食物,如果是则增加得分,重新生成食物,增加蛇身的长度。
- 使用
-
绘制 (
draw
函数):- 使用
clear
函数清空屏幕。 - 使用
printw
函数输出字符。 - 使用
refresh
函数刷新屏幕。 - 输出游戏画面,包括墙、蛇头、食物和蛇身。
- 输出得分信息。
- 使用
-
初始化和关闭 curses (
initscr
和endwin
函数):initscr
: 初始化 curses 库。keypad
: 启用键盘输入。nodelay
: 设置非阻塞输入。noecho
: 关闭回显。endwin
: 关闭 curses 库。
-
编译和运行:
- 使用
gcc
编译器编译程序,并链接ncurses
库。 - 运行生成的可执行文件。
- 使用
四、继续完善
这段贪食蛇游戏代码已经基本完成了一个简单的实现,但仍然有一些方面可以改进和完善,具体包括:
-
边界检查:
当蛇头移动到边界时,游戏会结束。可以考虑在边界处实现蛇穿越的效果,即从一侧穿越到另一侧。 -
游戏难度递增:
目前游戏的难度保持不变,可以考虑逐渐增加蛇的移动速度或者加快食物的生成速度,使得游戏更具挑战性。 -
碰撞检测:
目前只有边界碰撞检测和食物碰撞检测,可以考虑添加对蛇头与蛇身碰撞的检测,以防止游戏结束。 -
游戏结束提示:
当游戏结束时,可以输出更友好的提示信息,告诉玩家是因为碰到墙还是碰到自己身体而导致游戏结束。 -
代码结构和模块化:
将代码进一步模块化,使得各部分功能更清晰、易读、易于维护。可以考虑将一些功能性代码抽象成函数。 -
用户界面交互:
添加开始界面和游戏结束后的界面,以提供更良好的用户体验。 -
更多游戏元素:
考虑添加更多的游戏元素,如障碍物、特殊道具等,以增加游戏的趣味性和多样性。
这些功能给大家作为练习去实现。