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));
相关推荐
博客180019 小时前
酷宝的使用方法,超好用的免费界面库,C++、MFC可用
c++·mfc·界面库·库来帮·酷宝
郝学胜_神的一滴20 小时前
CMake 026:属性体系精讲、四大作用域全解 & 实战代码落地
c++·cmake
Sokach101520 小时前
Linux Shell 脚本从零到能用:一个新手的一天学习总结
linux
nujnewnehc1 天前
不会 py, 用 ai 写了个游戏辅助的感受
人工智能·游戏
AlfredZhao2 天前
Docker 容器时区不对,`timedatectl` 不存在怎么办?
linux·timezone
众少成多积小致巨2 天前
JNI (Java Native Interface) 技术手册中文参考指南
android·java·c++
jump_jump2 天前
为了重玩金庸群侠传,我研究了一下 Ruffle 怎么复活 Flash
游戏·rust·github
zzzzzz3103 天前
9K Star 炸裂开源!这个 C 语言写的代码知识图谱,把 Linux 内核索引压缩到了 3 分钟
linux·服务器·sql
XIAOHEZIcode3 天前
Linux系统鼠标偏移常见原因以及修复方案
linux·运维·游戏
Aloys_Code4 天前
逆向一个被遗忘的DVD游戏格式:从DES加密到Rust模拟器
游戏·模拟器·retroarch·复古游戏·native32·sunplus·赤刃·钢铁风暴