C语言如何实现treasure hunt寻宝游戏?

99ANYc3cd6
预计阅读时长 29 分钟
位置: 首页 C语言 正文
  1. 地图:一个二维数组表示的地图,包含玩家、宝藏、陷阱和空地。
  2. 玩家:可以在地图上移动(上下左右)。
  3. 目标:找到宝藏,同时避开陷阱。
  4. 交互:通过键盘输入控制玩家移动。
  5. 状态:显示当前步数、游戏状态(进行中/胜利/失败)。

游戏设计

地图元素

我们可以用不同的字符来表示地图上的不同元素:

treasure hunt c语言
(图片来源网络,侵删)
  • P: 玩家
  • T: 宝藏
  • X: 陷阱
  • 空地
  • 边界(可选,用于限制玩家移动范围)

游戏逻辑

  1. 初始化地图,随机放置玩家、宝藏和陷阱。
  2. 显示初始地图和游戏信息(如步数)。
  3. 进入一个循环,等待玩家输入方向键(W, A, S, D 或方向键)。
  4. 根据输入更新玩家位置。
  5. 检查玩家新位置的内容:
    • 如果是 ,则正常移动,步数+1。
    • 如果是 T,则玩家获胜,游戏结束。
    • 如果是 X,则玩家失败,游戏结束。
  6. 更新地图显示和游戏信息,然后继续循环。

C 语言代码实现

下面是一个完整的、可运行的 C 语言代码,你可以直接复制到你的 C 编译器(如 GCC, Clang, MSVC)中运行。

#include <stdio.h>
#include <stdlib.h> // 用于 rand() 和 srand()
#include <time.h>   // 用于 time()
#include <conio.h>  // 用于 _kbhit() 和 _getch() (Windows平台)
// #include <unistd.h> // 用于 usleep() (Linux/macOS平台)
// #include <termios.h> // 用于设置终端为无缓冲模式 (Linux/macOS平台)
// 定义地图大小
#define MAP_WIDTH  10
#define MAP_HEIGHT 8
// 定义地图元素
#define PLAYER      'P'
#define TREASURE    'T'
#define TRAP       'X'
#define EMPTY      '.'
#define BOUNDARY   '#'
// 函数声明
void initializeMap(char map[MAP_HEIGHT][MAP_WIDTH], int *playerX, int *playerY);
void printMap(char map[MAP_HEIGHT][MAP_WIDTH], int steps);
void clearScreen();
int main() {
    // 初始化随机数种子,确保每次运行地图都不同
    srand((unsigned int)time(NULL));
    char map[MAP_HEIGHT][MAP_WIDTH];
    int playerX, playerY;
    int steps = 0;
    char input;
    // 初始化游戏
    initializeMap(map, &playerX, &playerY);
    clearScreen();
    // 游戏主循环
    while (1) {
        printMap(map, steps);
        // 检查是否按下了键
        if (_kbhit()) {
            input = _getch(); // 获取按键,不显示在控制台
            // 计算新位置
            int newX = playerX;
            int newY = playerY;
            switch (input) {
                case 'w': // 上
                case 'W':
                case 72: // 上箭头
                    newY--;
                    break;
                case 's': // 下
                case 'S':
                case 80: // 下箭头
                    newY++;
                    break;
                case 'a': // 左
                case 'A':
                case 75: // 左箭头
                    newX--;
                    break;
                case 'd': // 右
                case 'D':
                case 77: // 右箭头
                    newX++;
                    break;
                case 'q': // 退出游戏
                case 'Q':
                    printf("\n游戏已退出,感谢游玩!\n");
                    return 0;
                default:
                    continue; // 按了其他键,忽略
            }
            // 检查新位置是否有效(不能是边界)
            if (map[newY][newX] != BOUNDARY) {
                // 清除旧位置的玩家标记
                map[playerY][playerX] = EMPTY;
                // 检查新位置的内容
                if (map[newY][newX] == TREASURE) {
                    printf("\n恭喜!你找到了宝藏!\n");
                    printf("你总共用了 %d 步,\n", steps + 1);
                    return 0; // 游戏胜利,退出
                } else if (map[newY][newX] == TRAP) {
                    printf("\n哎呀!你踩到了陷阱!游戏结束,\n");
                    printf("你总共用了 %d 步,\n", steps + 1);
                    return 0; // 游戏失败,退出
                }
                // 更新玩家位置
                playerX = newX;
                playerY = newY;
                map[playerY][playerX] = PLAYER;
                steps++;
            }
        }
        // 短暂暂停,避免CPU占用过高
        // Windows: Sleep(100);
        // Linux/macOS: usleep(100000);
    }
    return 0;
}
/**
 * @brief 初始化地图,放置玩家、宝藏和陷阱
 * @param map 二维数组地图
 * @param playerX 玩家的X坐标(输出参数)
 * @param playerY 玩家的Y坐标(输出参数)
 */
void initializeMap(char map[MAP_HEIGHT][MAP_WIDTH], int *playerX, int *playerY) {
    // 1. 填充地图为空地
    for (int y = 0; y < MAP_HEIGHT; y++) {
        for (int x = 0; x < MAP_WIDTH; x++) {
            map[y][x] = EMPTY;
        }
    }
    // 2. 设置边界
    for (int x = 0; x < MAP_WIDTH; x++) {
        map[0][x] = BOUNDARY;
        map[MAP_HEIGHT - 1][x] = BOUNDARY;
    }
    for (int y = 0; y < MAP_HEIGHT; y++) {
        map[y][0] = BOUNDARY;
        map[y][MAP_WIDTH - 1] = BOUNDARY;
    }
    // 3. 随机放置玩家
    *playerX = rand() % (MAP_WIDTH - 2) + 1;
    *playerY = rand() % (MAP_HEIGHT - 2) + 1;
    map[*playerY][*playerX] = PLAYER;
    // 4. 随机放置宝藏 (确保不与玩家重叠)
    int treasureX, treasureY;
    do {
        treasureX = rand() % (MAP_WIDTH - 2) + 1;
        treasureY = rand() % (MAP_HEIGHT - 2) + 1;
    } while (treasureX == *playerX && treasureY == *playerY);
    map[treasureY][treasureX] = TREASURE;
    // 5. 随机放置陷阱 (确保不与玩家和宝藏重叠)
    int numTraps = 5; // 陷阱数量
    for (int i = 0; i < numTraps; i++) {
        int trapX, trapY;
        do {
            trapX = rand() % (MAP_WIDTH - 2) + 1;
            trapY = rand() % (MAP_HEIGHT - 2) + 1;
        } while (map[trapY][trapX] != EMPTY); // 只能放在空地上
        map[trapY][trapX] = TRAP;
    }
}
/**
 * @brief 打印当前地图和游戏信息
 * @param map 二维数组地图
 * @param steps 当前步数
 */
void printMap(char map[MAP_HEIGHT][MAP_WIDTH], int steps) {
    clearScreen();
    printf("===== 寻宝游戏 =====\n");
    printf("使用 W/A/S/D 或方向键移动,Q 退出,\n");
    printf("P=玩家, T=宝藏, X=陷阱, #=边界\n");
    printf("当前步数: %d\n\n", steps);
    for (int y = 0; y < MAP_HEIGHT; y++) {
        for (int x = 0; x < MAP_WIDTH; x++) {
            printf("%c ", map[y][x]);
        }
        printf("\n");
    }
}
/**
 * @brief 清空控制台屏幕
 */
void clearScreen() {
    // Windows系统
    system("cls");
    // Linux/macOS系统
    // system("clear");
}

如何编译和运行

  1. 保存代码:将上面的代码保存为一个文件,treasure_hunt.c
  2. 编译
    • 如果你使用的是 GCC (在 Linux, macOS 或 Windows 的 MinGW/Cygwin 中),打开终端或命令提示符,输入:
      gcc treasure_hunt.c -o treasure_hunt
    • 如果你使用的是 Visual Studio,创建一个新的 C++ 控制台项目,并将代码粘贴到 .c 文件中,然后生成并运行。
  3. 运行
    • 在终端或命令提示符中,输入:
      ./treasure_hunt
    • 在 Visual Studio 中,直接按 F5 或点击“开始调试”按钮。

代码解释

  • #include:引入标准库和特定平台的库。
    • stdio.h:用于输入输出,如 printf
    • stdlib.h:用于 rand(生成随机数)和 srand(设置随机种子)。
    • time.h:用于 time 函数,为 srand 提供一个变化的种子。
    • conio.h:这是 Windows 平台特有的头文件,提供了 _kbhit()(检查是否有按键)和 _getch()(获取一个按键)这两个非常有用的函数,可以实现“无回显”的键盘输入,让游戏体验更好。
  • #define:定义常量,方便修改地图大小和元素符号。
  • main() 函数:游戏的主入口。
    • srand((unsigned int)time(NULL));:初始化随机数生成器。time(NULL) 返回当前时间的秒数,作为种子,确保每次运行程序时地图布局都不同。
    • initializeMap():调用函数来设置游戏初始状态。
    • while(1):一个无限循环,代表游戏持续进行,直到玩家获胜、失败或主动退出。
    • _kbhit()_getch():这是游戏交互的核心。_kbhit() 检查用户是否按下了键盘上的任意键,如果按下了,_getch() 就会读取这个键的值,并且不会把字符显示在屏幕上。
    • switch(input):根据玩家按下的键,更新玩家将要移动到的 newXnewY 坐标。
    • 边界检查if (map[newY][newX] != BOUNDARY) 确保玩家不能穿过墙壁。
    • 移动逻辑
      1. map[playerY][playerX] = EMPTY;:将玩家原来的位置变为空地。
      2. if (map[newY][newX] == TREASURE):判断新位置是否是宝藏。
      3. if (map[newY][newX] == TRAP):判断新位置是否是陷阱。
      4. 如果是普通空地,则更新玩家坐标 playerX, playerY,并在新位置画上玩家 map[playerY][playerX] = PLAYER
  • initializeMap() 函数
    • 首先用 EMPTY 填满整个地图。
    • 然后用 BOUNDARY 画出地图的边框。
    • 使用 rand() 随机生成玩家、宝藏和陷阱的坐标,注意,放置宝藏和陷阱时,使用 do-while 循环确保它们不会出现在同一个位置,也不会和玩家重叠。
  • printMap() 函数
    • 首先调用 clearScreen() 清空屏幕,使每次显示的地图都是“刷新”过的,不会留下上一次的痕迹。
    • 然后打印游戏标题、操作说明和当前步数。
    • 通过两层嵌套的 for 循环,将二维地图数组的内容逐行逐个字符地打印出来。
  • clearScreen() 函数
    • 使用 system("cls") 命令来清空 Windows 控制台,如果你在 Linux 或 macOS 上,需要使用 system("clear")

跨平台兼容性说明

上面的代码使用了 conio.h,这在 Windows 上是完美工作的,如果你想在 LinuxmacOS 上运行,你需要做以下修改:

  1. 注释掉 #include <conio.h>
  2. 替换输入检测部分:Linux/macOS 没有原生的 _kbhit()_getch(),你需要自己实现类似的功能,通常需要设置终端为“无缓冲”模式。

一个跨平台的替代方案是使用 ncurses,这是一个功能强大的终端屏幕处理库,可以非常方便地处理键盘输入和屏幕绘制,但使用 ncurses 需要额外安装库,并且代码会稍微复杂一些。

对于这个简单的示例,直接使用 scanfgetchar 会因为需要按回车而体验不佳,如果你主要在 Windows 上开发,当前代码是最好的选择,如果你希望代码能在所有平台上流畅运行,学习 ncurses 是一个很好的方向。

treasure hunt c语言
(图片来源网络,侵删)
treasure hunt c语言
(图片来源网络,侵删)
-- 展开阅读全文 --
头像
C语言中double类型round函数如何使用?
« 上一篇 12-07
dede channel runphp
下一篇 » 12-07

相关文章

取消
微信二维码
支付宝二维码

目录[+]