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(" "); 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(" "); } for (int i = 0; i < WIDTH + 2; i++) printw("#"); printw(" "); 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 库。 - 运行生成的可执行文件。
- 使用
四、继续完善
这段贪食蛇游戏代码已经基本完成了一个简单的实现,但仍然有一些方面可以改进和完善,具体包括:
-
边界检查:
当蛇头移动到边界时,游戏会结束。可以考虑在边界处实现蛇穿越的效果,即从一侧穿越到另一侧。
-
游戏难度递增:
目前游戏的难度保持不变,可以考虑逐渐增加蛇的移动速度或者加快食物的生成速度,使得游戏更具挑战性。
-
碰撞检测:
目前只有边界碰撞检测和食物碰撞检测,可以考虑添加对蛇头与蛇身碰撞的检测,以防止游戏结束。
-
游戏结束提示:
当游戏结束时,可以输出更友好的提示信息,告诉玩家是因为碰到墙还是碰到自己身体而导致游戏结束。
-
代码结构和模块化:
将代码进一步模块化,使得各部分功能更清晰、易读、易于维护。可以考虑将一些功能性代码抽象成函数。
-
用户界面交互:
添加开始界面和游戏结束后的界面,以提供更良好的用户体验。
-
更多游戏元素:
考虑添加更多的游戏元素,如障碍物、特殊道具等,以增加游戏的趣味性和多样性。
这些功能给大家作为练习去实现。