qt小游戏贪吃蛇

效果展示图

pro文件

cpp 复制代码
QT += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

TARGET = snake_game
TEMPLATE = app

HEADERS += snakewidget.h

SOURCES += main.cpp \
    snakewidget.cpp

头文件 snakewidget.h

cpp 复制代码
#ifndef SNAKEWIDGET_H
#define SNAKEWIDGET_H

#include <QWidget>
#include <QTimer>
#include <QKeyEvent>
#include <QPainter>
#include <QRandomGenerator>
#include <QFile>
#include <QTextStream>

class SnakeWidget : public QWidget {
    Q_OBJECT

public:
    explicit SnakeWidget(QWidget *parent = nullptr);

protected:
    void paintEvent(QPaintEvent *event) override;
    void keyPressEvent(QKeyEvent *event) override;
    void timerEvent(QTimerEvent *event) override;

private:
    void initGame();
    void startGame();
    void pauseGame();
    void gameOver();
    void checkApple();
    void move();
    void locateApple();
    void drawSnake(QPainter &painter);
    void drawApple(QPainter &painter);
    void loadHighScore();
    void saveHighScore();
    void closeEvent(QCloseEvent *event) override;

    struct Segment {
        int x, y;
        Segment(int x = 0, int y = 0) : x(x), y(y) {}
    };

    static const int CELL_SIZE = 20;
    static const int BOARD_WIDTH = 30;
    static const int BOARD_HEIGHT = 20;

    QVector<Segment> snake;
    Segment apple;
    int direction;
    int nextDirection;
    int score;
    int highScore;
    bool gameOverFlag;
    bool paused;
    int timerId;
    QTimer *gameTimer;
};

#endif // SNAKEWIDGET_H

源文件 snakewidget.cpp main.cpp

cpp 复制代码
#include "snakewidget.h"
#include <QMessageBox>
#include <QFontMetrics>
#include <QCoreApplication>
#include <QDebug>

SnakeWidget::SnakeWidget(QWidget *parent) : QWidget(parent) {
    setFixedSize(BOARD_WIDTH * CELL_SIZE, BOARD_HEIGHT * CELL_SIZE);
    setWindowTitle("贪吃蛇游戏");

    gameTimer = new QTimer(this);
    connect(gameTimer, &QTimer::timeout, this, [this]() {
        move();
        checkApple();
        update();
    });

    // 初始化最高分为0,然后尝试加载保存的最高分
    highScore = 0;
    loadHighScore();
    initGame();

    // 自动开始游戏
    startGame();
}

void SnakeWidget::initGame() {
    snake.clear();
    snake.append(Segment(BOARD_WIDTH / 2, BOARD_HEIGHT / 2));
    snake.append(Segment(BOARD_WIDTH / 2 - 1, BOARD_HEIGHT / 2));
    snake.append(Segment(BOARD_WIDTH / 2 - 2, BOARD_HEIGHT / 2));

    direction = Qt::Key_Right;
    nextDirection = Qt::Key_Right;
    score = 0;
    gameOverFlag = false;
    paused = true;  // 初始化为暂停状态,等待用户开始

    locateApple();
}

void SnakeWidget::startGame() {
    if (gameOverFlag) {
        initGame();
    }

    paused = false;
    gameOverFlag = false;
    gameTimer->start(200); // 每100毫秒更新一次
}

void SnakeWidget::pauseGame() {
    if (!gameOverFlag) {
        paused = !paused;
        if (paused) {
            gameTimer->stop();
        } else {
            gameTimer->start();
        }
        update();
    }
}

void SnakeWidget::gameOver() {
    gameTimer->stop();
    gameOverFlag = true;

    // 更新最高分
    if (score > highScore) {
        highScore = score;
        // 保存最高分到文件
        saveHighScore();
    }

    QMessageBox msgBox;
    msgBox.setWindowTitle("游戏结束");
    msgBox.setText(QString("游戏结束!你的得分是: %1\n最高分: %2").arg(score).arg(highScore));
    msgBox.setStandardButtons(QMessageBox::Ok);
    msgBox.exec();

    startGame();
}

void SnakeWidget::checkApple() {
    if (snake.first().x == apple.x && snake.first().y == apple.y) {
        score += 10;
        if (score > highScore) {
            highScore = score;
        }

        // 增加蛇的长度
        Segment tail = snake.last();
        snake.append(tail);

        locateApple();
    }
}

void SnakeWidget::move() {
    // 更新方向
    direction = nextDirection;

    // 计算新的头部位置
    Segment head = snake.first();
    Segment newHead = head;

    switch (direction) {
        case Qt::Key_Up:
            newHead.y--;
            break;
        case Qt::Key_Down:
            newHead.y++;
            break;
        case Qt::Key_Left:
            newHead.x--;
            break;
        case Qt::Key_Right:
            newHead.x++;
            break;
    }

    // 检查是否撞墙
    if (newHead.x < 0 || newHead.x >= BOARD_WIDTH ||
        newHead.y < 0 || newHead.y >= BOARD_HEIGHT) {
        gameOver();
        return;
    }

    // 检查是否撞到自己的身体
    for (int i = 1; i < snake.size(); i++) {
        if (newHead.x == snake[i].x && newHead.y == snake[i].y) {
            gameOver();
            return;
        }
    }

    // 移动蛇
    snake.insert(0, newHead);
    snake.removeLast();
}

void SnakeWidget::locateApple() {
    bool validPosition = false;

    while (!validPosition) {
        int x = QRandomGenerator::global()->bounded(BOARD_WIDTH);
        int y = QRandomGenerator::global()->bounded(BOARD_HEIGHT);

        validPosition = true;

        // 检查苹果是否在蛇的身体上
        for (const Segment &segment : snake) {
            if (segment.x == x && segment.y == y) {
                validPosition = false;
                break;
            }
        }

        if (validPosition) {
            apple.x = x;
            apple.y = y;
        }
    }
}

void SnakeWidget::drawSnake(QPainter &painter) {
    // 绘制更立体的蛇身
    for (int i = 0; i < snake.size(); i++) {
        const Segment &segment = snake[i];
        QRectF rect(segment.x * CELL_SIZE, segment.y * CELL_SIZE,
                   CELL_SIZE - 1, CELL_SIZE - 1);

        // 创建渐变效果
        QLinearGradient gradient(rect.topLeft(), rect.bottomRight());
        gradient.setColorAt(0, QColor(100, 200, 100));  // 亮绿色
        gradient.setColorAt(1, QColor(0, 100, 0));      // 深绿色

        painter.setBrush(gradient);
        painter.setPen(QPen(Qt::darkGreen, 1, Qt::SolidLine));

        // 绘制圆角矩形,让蛇身更圆润
        painter.drawRoundedRect(rect, 5, 5);

        // 添加高光效果
        painter.setBrush(QColor(150, 255, 150, 100));
        painter.drawEllipse(rect.x() + 2, rect.y() + 2, 8, 8);
    }

    // 绘制更生动的蛇头
    Segment head = snake.first();
    QRectF headRect(head.x * CELL_SIZE, head.y * CELL_SIZE,
                   CELL_SIZE - 1, CELL_SIZE - 1);

    // 蛇头渐变
    QLinearGradient headGradient(headRect.topLeft(), headRect.bottomRight());
    headGradient.setColorAt(0, QColor(120, 220, 120));
    headGradient.setColorAt(1, QColor(20, 120, 20));

    painter.setBrush(headGradient);
    painter.setPen(QPen(Qt::black, 1, Qt::SolidLine));
    painter.drawRoundedRect(headRect, 6, 6);

    // 画更逼真的蛇的眼睛
    painter.setBrush(Qt::white);
    painter.setPen(Qt::black);

    if (direction == Qt::Key_Up) {
        // 上方向时的眼睛
        painter.drawEllipse(head.x * CELL_SIZE + 5, head.y * CELL_SIZE + 3, 8, 10);
        painter.drawEllipse(head.x * CELL_SIZE + CELL_SIZE - 9, head.y * CELL_SIZE + 3, 8, 10);
        painter.setBrush(Qt::black);
        painter.drawEllipse(head.x * CELL_SIZE + 7, head.y * CELL_SIZE + 5, 4, 6);
        painter.drawEllipse(head.x * CELL_SIZE + CELL_SIZE - 7, head.y * CELL_SIZE + 5, 4, 6);
    } else if (direction == Qt::Key_Down) {
        // 下方向时的眼睛
        painter.drawEllipse(head.x * CELL_SIZE + 5, head.y * CELL_SIZE + CELL_SIZE - 7, 8, 10);
        painter.drawEllipse(head.x * CELL_SIZE + CELL_SIZE - 9, head.y * CELL_SIZE + CELL_SIZE - 7, 8, 10);
        painter.setBrush(Qt::black);
        painter.drawEllipse(head.x * CELL_SIZE + 7, head.y * CELL_SIZE + CELL_SIZE - 5, 4, 6);
        painter.drawEllipse(head.x * CELL_SIZE + CELL_SIZE - 7, head.y * CELL_SIZE + CELL_SIZE - 5, 4, 6);
    } else if (direction == Qt::Key_Left) {
        // 左方向时的眼睛
        painter.drawEllipse(head.x * CELL_SIZE + 3, head.y * CELL_SIZE + 5, 10, 8);
        painter.drawEllipse(head.x * CELL_SIZE + 3, head.y * CELL_SIZE + CELL_SIZE - 9, 10, 8);
        painter.setBrush(Qt::black);
        painter.drawEllipse(head.x * CELL_SIZE + 5, head.y * CELL_SIZE + 7, 6, 4);
        painter.drawEllipse(head.x * CELL_SIZE + 5, head.y * CELL_SIZE + CELL_SIZE - 7, 6, 4);
    } else {
        // 右方向时的眼睛(默认)
        painter.drawEllipse(head.x * CELL_SIZE + CELL_SIZE - 7, head.y * CELL_SIZE + 5, 10, 8);
        painter.drawEllipse(head.x * CELL_SIZE + CELL_SIZE - 7, head.y * CELL_SIZE + CELL_SIZE - 9, 10, 8);
        painter.setBrush(Qt::black);
        painter.drawEllipse(head.x * CELL_SIZE + CELL_SIZE - 5, head.y * CELL_SIZE + 7, 6, 4);
        painter.drawEllipse(head.x * CELL_SIZE + CELL_SIZE - 5, head.y * CELL_SIZE + CELL_SIZE - 7, 6, 4);
    }
}

void SnakeWidget::drawApple(QPainter &painter) {
    QRectF appleRect(apple.x * CELL_SIZE, apple.y * CELL_SIZE,
                    CELL_SIZE, CELL_SIZE);

    // 创建苹果的渐变效果
    QRadialGradient gradient(appleRect.center(), CELL_SIZE / 2);
    gradient.setColorAt(0, QColor(255, 100, 100));    // 亮红色
    gradient.setColorAt(0.7, QColor(200, 0, 0));      // 深红色
    gradient.setColorAt(1, QColor(100, 0, 0));        // 最深的红色

    painter.setBrush(gradient);
    painter.setPen(QPen(QColor(150, 0, 0), 1, Qt::SolidLine));

    // 绘制苹果主体
    painter.drawEllipse(appleRect);

    // 添加苹果的高光
    painter.setBrush(QColor(255, 180, 180, 150));
    painter.drawEllipse(apple.x * CELL_SIZE + 3, apple.y * CELL_SIZE + 3, 10, 12);

    // 添加苹果蒂
    painter.setBrush(QColor(100, 50, 0));
    painter.setPen(QPen(QColor(80, 40, 0), 1, Qt::SolidLine));
    painter.drawRect(apple.x * CELL_SIZE + CELL_SIZE / 2 - 2,
                    apple.y * CELL_SIZE - 2, 4, 6);

    // 添加苹果叶子
    painter.setBrush(QColor(50, 150, 50));
    painter.setPen(QPen(QColor(30, 100, 30), 1, Qt::SolidLine));
    painter.drawEllipse(apple.x * CELL_SIZE + CELL_SIZE / 2 - 3,
                       apple.y * CELL_SIZE - 4, 6, 4);
}

void SnakeWidget::paintEvent(QPaintEvent *event) {
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);

    // 绘制渐变背景
    QLinearGradient backgroundGradient(0, 0, 0, height());
    backgroundGradient.setColorAt(0, QColor(240, 240, 240));  // 亮灰色
    backgroundGradient.setColorAt(1, QColor(200, 200, 200));  // 深灰色

    painter.setBrush(backgroundGradient);
    painter.setPen(Qt::NoPen);
    painter.drawRect(rect());

    // 绘制网格背景
    painter.setPen(QPen(QColor(180, 180, 180), 1, Qt::DashLine));
    for (int x = 0; x < BOARD_WIDTH; x++) {
        painter.drawLine(x * CELL_SIZE, 0, x * CELL_SIZE, BOARD_HEIGHT * CELL_SIZE);
    }
    for (int y = 0; y < BOARD_HEIGHT; y++) {
        painter.drawLine(0, y * CELL_SIZE, BOARD_WIDTH * CELL_SIZE, y * CELL_SIZE);
    }

    // 绘制游戏元素
    drawSnake(painter);
    drawApple(painter);

    // 绘制分数
    painter.setPen(Qt::black);
    painter.setFont(QFont("Arial", 12));
    painter.drawText(10, 20, QString("得分: %1").arg(score));
    painter.drawText(10, 40, QString("最高分: %1").arg(highScore));

    // 绘制游戏规则和操作说明
    painter.setPen(Qt::darkBlue);
    painter.setFont(QFont("Arial", 10));
    painter.drawText(10, height() - 60, "游戏规则:");
    painter.drawText(10, height() - 45, "• 吃苹果得分,每颗苹果+10分");
    painter.drawText(10, height() - 30, "• 撞墙或撞到自己游戏结束");
    painter.drawText(10, height() - 15, "操作:方向键移动,空格键暂停/开始");

    // 绘制游戏开始提示
    if (paused && !gameOverFlag) {
        painter.setPen(Qt::red);
        painter.setFont(QFont("Arial", 24, QFont::Bold));
        QString pauseText = "游戏暂停";
        QFontMetrics metrics(painter.font());
        int textWidth = metrics.width(pauseText);
        int textHeight = metrics.height();
        painter.drawText((width() - textWidth) / 2, (height() + textHeight) / 2 - 30, pauseText);

        // 添加操作提示
        painter.setPen(Qt::blue);
        painter.setFont(QFont("Arial", 14));
        QString hintText = "按空格键开始/继续游戏";
        QFontMetrics hintMetrics(painter.font());
        int hintWidth = hintMetrics.width(hintText);
        painter.drawText((width() - hintWidth) / 2, (height() + hintMetrics.height()) / 2 + 10, hintText);

        hintText = "按方向键控制蛇的移动";
        hintWidth = hintMetrics.width(hintText);
        painter.drawText((width() - hintWidth) / 2, (height() + hintMetrics.height()) / 2 + 35, hintText);
    }
}

void SnakeWidget::keyPressEvent(QKeyEvent *event) {
    int key = event->key();

    if (key == Qt::Key_Space) {
        if (!gameOverFlag) {  // 只有游戏中才能暂停
            pauseGame();
        }
        return;
    }

    // 游戏结束状态下的处理
    if (gameOverFlag) {
        if (key == Qt::Key_Return || key == Qt::Key_Enter) {
            startGame();
        }
        return;
    }

    // 暂停状态下的处理
    if (paused) {
        if (key == Qt::Key_Return || key == Qt::Key_Enter) {
            startGame();
        }
        return;
    }

    // 正常游戏中的方向控制(不能直接反向)
    switch (key) {
        case Qt::Key_Up:
            if (direction != Qt::Key_Down) nextDirection = Qt::Key_Up;
            break;
        case Qt::Key_Down:
            if (direction != Qt::Key_Up) nextDirection = Qt::Key_Down;
            break;
        case Qt::Key_Left:
            if (direction != Qt::Key_Right) nextDirection = Qt::Key_Left;
            break;
        case Qt::Key_Right:
            if (direction != Qt::Key_Left) nextDirection = Qt::Key_Right;
            break;
    }
}

void SnakeWidget::timerEvent(QTimerEvent *event) {
    if (event->timerId() == timerId) {
        move();
        checkApple();
        update();
    }
    QWidget::timerEvent(event);
}

void SnakeWidget::loadHighScore() {
    QString fileName = QCoreApplication::applicationDirPath() + "/snake_highscore.txt";
    QFile file(fileName);
    if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        QTextStream in(&file);
        QString line = in.readLine();
        bool ok;
        int savedScore = line.toInt(&ok);
        if (ok) {
            highScore = savedScore;
        }
        file.close();
    }
}

void SnakeWidget::saveHighScore() {
    QString fileName = QCoreApplication::applicationDirPath() + "/snake_highscore.txt";
    QFile file(fileName);
    if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        QTextStream out(&file);
        out << highScore;
        qDebug() << highScore;
        file.close();
        qDebug() << "High score saved:" << highScore << "to" << fileName;
    } else {
        qDebug() << "Failed to save high score to" << fileName;
    }
}

void SnakeWidget::closeEvent(QCloseEvent *event) {
    // 保存当前最高分到文件
    saveHighScore();

    // 显示确认对话框
    QMessageBox::StandardButton btn = QMessageBox::question(
        this,
        "确认退出",
        "确定要退出游戏吗?",
        QMessageBox::Yes | QMessageBox::No
    );

    if (btn == QMessageBox::Yes) {
        event->accept();
    } else {
        event->ignore();
    }
}
cpp 复制代码
#include <QApplication>
#include <QCoreApplication>
#include "snakewidget.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    SnakeWidget w;
    w.show();
    return a.exec();
}
相关推荐
我在人间贩卖青春2 小时前
Qt 项目发布
qt·项目发布
不才小强7 小时前
Qt开发实战:屏幕录制项目中学习到的知识与遇到的难题
qt·音视频
人还是要有梦想的8 小时前
QT的基本学习路线
开发语言·qt·学习
艾莉丝努力练剑8 小时前
【QT】QT快捷键整理
linux·运维·服务器·开发语言·图像处理·人工智能·qt
黑化暴龙魔神--幻梦8 小时前
QT使用TRANSLATIONS添加多国翻译(详细过程)
qt·自动翻译
程序员_大白8 小时前
【2025版】最新Qt下载安装及配置教程(非常详细)零基础入门到精通,收藏这篇就够了
开发语言·qt
我在人间贩卖青春8 小时前
Qt多媒体编程
qt·多媒体编程
高亚奇8 小时前
QT版本 MSVC/MinGW/GCC 含义及如何区分
开发语言·qt
IdahoFalls8 小时前
QT-Windows Kits-版本问题:【“_mm_loadu_si64”: 找不到标识符】解决方案[NEW]
开发语言·c++·windows·qt·算法·visual studio
希忘auto8 小时前
详解关于VS配置好Qt环境之后但无法打开ui界面
qt·vs