前两篇我们一直在"猜"和"算",这一篇开始有真正的空间感。文本迷宫把地图存进二维数组,玩家用 WASD 控制 @ 穿行,走到出口 E 即通关。你将学到 C 语言最实用的数据结构——二维数组,以及"位置 + 碰撞检测"这套游戏开发的核心思想。
玩法介绍
终端打印由 #(墙)和 .(路)组成的地图,角色 @ 从 S 出发,按 W/A/S/D 上下左右移动,撞墙会收到提示,走到 E 通关。地图就是一段 10 行 × 20 列的字符数组,你可以亲手修改它,设计自己的迷宫。
第 1 步:用二维数组定义地图
把地图写成字符串数组:maze[ROWS][COLS + 1] 的 +1 留给字符串结尾 \0。玩家坐标 px(列)、py(行)从 S 所在格出发。
#include <stdio.h>
#define ROWS 10
#define COLS 20
/* 地图: # 墙, . 路, S 起点, E 终点 */
char maze[ROWS][COLS + 1] = {
"####################",
"#S........#........#",
"#.###.####.#.####..#",
"#.#......#.#.#.....#",
"#.#.####.#.#.#.###.#",
"#.#.#....#...#...#.#",
"#.#.#.######.###.#.#",
"#...#...........####",
"#####.#####.########",
"#.....#..........E.#"
};
int px = 1, py = 1; /* 玩家位置(列, 行) */
第 2 步:打印地图与玩家位置
双层 for 循环逐行逐列输出,轮到玩家所在格就打印 @ 而不是地图字符。这就是"渲染"——把游戏状态画到屏幕上。
void print_maze(void) {
int x, y;
for (y = 0; y < ROWS; y++) {
for (x = 0; x < COLS; x++) {
if (x == px && y == py)
putchar('@'); /* 玩家所在位置 */
else
putchar(maze[y][x]);
}
putchar('\n');
}
}
第 3 步:读取按键输入
getchar() 读一个字符,switch 把它翻译成坐标变化。注意输入后的回车会残留在缓冲区,要用 while (getchar() != '\n') 吃掉,否则下一轮会读到"幽灵回车"。
cmd = getchar();
while (getchar() != '\n'); /* 吃掉输入后的回车 */
switch (cmd) {
case 'w': case 'W': ny--; break; /* 上: 行号减 1 */
case 's': case 'S': ny++; break; /* 下: 行号加 1 */
case 'a': case 'A': nx--; break; /* 左: 列号减 1 */
case 'd': case 'D': nx++; break; /* 右: 列号加 1 */
case 'q': case 'Q': return 0;
default: continue;
}
第 4 步:移动与撞墙检测
先算出目标位置 (nx, ny),再判断:目标格是 # 就不移动,只提示;否则才更新坐标。"先检测、后行动"是所有游戏碰撞处理的通用套路。
if (maze[ny][nx] == '#') {
printf("前面是墙, 走不了!\n");
continue; /* 本次输入作废, 重新出方向 */
}
px = nx;
py = ny;
第 5 步:通关判定与完整代码
每次移动成功后检查当前位置:是 E 就打印地图、祝贺通关并结束循环。组装进 while (1) 主循环,就是完整的迷宫游戏:
#include <stdio.h>
#define ROWS 10
#define COLS 20
char maze[ROWS][COLS + 1] = {
"####################",
"#S........#........#",
"#.###.####.#.####..#",
"#.#......#.#.#.....#",
"#.#.####.#.#.#.###.#",
"#.#.#....#...#...#.#",
"#.#.#.######.###.#.#",
"#...#...........####",
"#####.#####.########",
"#.....#..........E.#"
};
int px = 1, py = 1;
void print_maze(void) {
int x, y;
for (y = 0; y < ROWS; y++) {
for (x = 0; x < COLS; x++) {
if (x == px && y == py)
putchar('@');
else
putchar(maze[y][x]);
}
putchar('\n');
}
}
int main(void) {
char cmd;
printf("文本迷宫: 用 W/A/S/D 移动, 走到 E 即可通关!\n\n");
while (1) {
int nx = px, ny = py;
print_maze();
printf("方向 (W上 A左 S下 D右, Q退出): ");
cmd = getchar();
while (getchar() != '\n');
switch (cmd) {
case 'w': case 'W': ny--; break;
case 's': case 'S': ny++; break;
case 'a': case 'A': nx--; break;
case 'd': case 'D': nx++; break;
case 'q': case 'Q': return 0;
default: continue;
}
if (maze[ny][nx] == '#') { /* 撞墙检测 */
printf("前面是墙, 走不了!\n");
continue;
}
px = nx;
py = ny;
if (maze[py][px] == 'E') { /* 到达终点 */
print_maze();
printf("恭喜通关! 你成功走出了迷宫!\n");
break;
}
}
return 0;
}
编译运行:
gcc -o maze maze.c
./maze
💡 改进方向:用"递归回溯"算法随机生成迷宫,每次开局都不同;加入宝箱和陷阱;统计并显示步数;把地图存进外部.txt文件用fscanf读入;再进阶一点,加入一只会追人的怪物。