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));
相关推荐
June`1 小时前
warp shuffle指令
c++·人工智能·算法·cuda
用什么都重名1 小时前
Ubuntu 24.04 安装 NVIDIA 驱动:解决 “NVIDIA-SMI has failed“ 报错全记录
linux·运维·ubuntu
Industio_触觉智能1 小时前
瑞芯微ISP内核驱动深度解析|RKISP39从架构到Probe初始化全流程(上篇)
linux·嵌入式硬件·硬件架构·摄像头·isp·瑞芯微·rk3576
有续技术1 小时前
三菱 (Mitsubishi) 机床 设置查看 IP 地址
linux·服务器·网络
乱七八糟的屋子1 小时前
【C++数值计算】NumCpp超详细入门教程(纯正Numpy语法、零学习成本、C++首选科学计算库、性能压测对比)
c++·数值计算·numpy·高性能计算·科学计算·ndarray
yagami_gagami1 小时前
第四届黄河流域公安院校电子物证个人赛服务器取证
linux·服务器·网络·mysql·安全·docker·llama
choumin1 小时前
C程序能调用extern “C“声明的带默认参数的C++函数吗?
c语言·c++·extern c·默认参数
邪修king1 小时前
Re:Linux系统篇(七) 开发工具篇 Chapter3:Makefile 从入门到精通 —— 依赖关系、伪目标、栈式推导与自动化构建全解
linux·运维·服务器·vim
bosins2 小时前
Ubuntu 日常最常用的文件操作场景和对应指令
linux·服务器·ubuntu
AmyLin_20012 小时前
PDF 色彩保真工程实践【3】上手实践:工程结构、依赖集成与一键构建运行
c++·visualstudio·pdf·zlib·vcpkg·libtiff·cmyk