Linux C++ 贪吃蛇游戏 -- 方向键控制蛇移动

1. 代码

复制代码
#include <iostream>
#include <ncurses.h>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <thread>

using namespace std;

// 定义方向
enum class Direction { UP, DOWN, LEFT, RIGHT };

class SnakeGame {
public:
    SnakeGame(int width, int height) : width(width), height(height), score(0), gameover(false) {
        srand(time(nullptr));
        initscr(); // 初始化终端
        keypad(stdscr, true); // 启用键盘输入
        noecho(); // 关闭回显
        nodelay(stdscr, true); // 非阻塞模式
        curs_set(0); // 隐藏光标
        getmaxyx(stdscr, max_y, max_x);
        window = newwin(height, width, (max_y - height) / 2, (max_x - width) / 2);
        box(window, 0, 0); // 绘制窗口边框
        refresh();
        wrefresh(window);
        generateFood();
        snake.push_back(make_pair(height / 2, width / 2)); // 初始化贪吃蛇位置
        drawSnake();
    }

    ~SnakeGame() {
        delwin(window);
        endwin();
    }

    void run() {
        // 游戏循环
        while (!gameover) {
            int ch = getch();
            handleInput(ch);
            moveSnake();
            checkCollision();
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
        }
        showGameOver();
    }

private:
    int width, height;
    int score;
    bool gameover;
    int max_x, max_y;
    WINDOW *window;
    vector<pair<int, int>> snake;
    pair<int, int> food;
    Direction direction = Direction::RIGHT;

    void generateFood() {
        do {
            food.first = rand() % (height - 2) + 1;
            food.second = rand() % (width - 2) + 1;
        } while (isSnakeCell(food.first, food.second));
        mvwaddch(window, food.first, food.second, '@');
        refresh();
        wrefresh(window);
    }

    void drawSnake() {
        for (const auto& cell : snake) {
            mvwaddch(window, cell.first, cell.second, '#');
        }
        refresh();
        wrefresh(window);
    }

    void moveSnake() {
        pair<int, int> head = snake.front();
        pair<int, int> newHead = head;

        switch (direction) {
            case Direction::UP:
                newHead.first--;
                break;
            case Direction::DOWN:
                newHead.first++;
                break;
            case Direction::LEFT:
                newHead.second--;
                break;
            case Direction::RIGHT:
                newHead.second++;
                break;
        }

        snake.insert(snake.begin(), newHead);
        mvwaddch(window, newHead.first, newHead.second, '#');
        refresh();
        wrefresh(window);

        if (newHead != food) {
            mvwaddch(window, snake.back().first, snake.back().second, ' ');
            snake.pop_back();
        } else {
            score++;
            generateFood();
        }
    }

    void handleInput(int ch) {
        switch (ch) {
            case KEY_UP:
                if (direction != Direction::DOWN) {
                    direction = Direction::UP;
                }
                break;
            case KEY_DOWN:
                if (direction != Direction::UP) {
                    direction = Direction::DOWN;
                }
                break;
            case KEY_LEFT:
                if (direction != Direction::RIGHT) {
                    direction = Direction::LEFT;
                }
                break;
            case KEY_RIGHT:
                if (direction != Direction::LEFT) {
                    direction = Direction::RIGHT;
                }
                break;
        }
    }

    void checkCollision() {
        pair<int, int> head = snake.front();

        // 检查是否撞墙
        if (head.first == 0 || head.first == height - 1 || head.second == 0 || head.second == width - 1) {
            gameover = true;
            return;
        }

        // 检查是否撞到自己的身体
        for (size_t i = 1; i < snake.size(); i++) {
            if (snake[i] == head) {
                gameover = true;
                return;
            }
        }
    }

    void showGameOver() {
        clear();
        string gameOverText = "Game Over!";
        mvprintw(max_y / 2, (max_x - gameOverText.length()) / 2, gameOverText.c_str());
        string scoreText = "Score: " + to_string(score);
        mvprintw(max_y / 2 + 1, (max_x - scoreText.length()) / 2, scoreText.c_str());
        refresh();
        getch();
    }

    bool isSnakeCell(int row, int col) {
        for (const auto& cell : snake) {
            if (cell.first == row && cell.second == col) {
                return true;
            }
        }
        return false;
    }
};

int main() {
    SnakeGame game(40, 20);
    game.run();
    return 0;
}

2. 编译命令

复制代码
alfred@ubuntu:~/c_learning/d_cplusplus_learning$ g++ -std=c++11 snake.cpp -o snake -lncurses

3. 运行游戏,使用方向键 ↑ ↓ ← → 上下左右控制蛇移动

复制代码
alfred@ubuntu:~/c_learning/d_cplusplus_learning$ ./snake

4. 调整蛇移动的速度

修改延时时间100,单位为ms,数字越小,移动越快,修改完后重新编译,运行

复制代码
std::this_thread::sleep_for(std::chrono::milliseconds(100));
相关推荐
肆忆_10 小时前
# 用 5 个问题学懂 C++ 虚函数(入门级)
c++
chlk12313 小时前
Linux文件权限完全图解:读懂 ls -l 和 chmod 755 背后的秘密
linux·操作系统
舒一笑13 小时前
Ubuntu系统安装CodeX出现问题
linux·后端
改一下配置文件14 小时前
Ubuntu24.04安装NVIDIA驱动完整指南(含Secure Boot解决方案)
linux
不想写代码的星星14 小时前
虚函数表:C++ 多态背后的那个男人
c++
xiezhr16 小时前
米哈游36岁程序员被曝复工当晚猝死出租屋内
游戏·程序员·游戏开发
深紫色的三北六号1 天前
Linux 服务器磁盘扩容与目录迁移:rsync + bind mount 实现服务无感迁移(无需修改配置)
linux·扩容·服务迁移
SudosuBash1 天前
[CS:APP 3e] 关于对 第 12 章 读/写者的一点思考和题解 (作业 12.19,12.20,12.21)
linux·并发·操作系统(os)
哈基咪怎么可能是AI2 天前
为什么我就想要「线性历史 + Signed Commits」GitHub 却把我当猴耍 🤬🎙️
linux·github
十日十行2 天前
Linux和window共享文件夹
linux