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();
}
相关推荐
用户8055336980320 小时前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner21 小时前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz6 天前
QML Hello World 入门示例
qt
xcyxiner9 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner10 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner10 天前
DicomViewer (添加模型类)3
qt
xcyxiner11 天前
DicomViewer (目录调整) 2
qt
xcyxiner11 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
桥田智能13 天前
桥田智能 QT-650S:面向白车身焊装的 800kg 重载快换解决方案
开发语言·qt·系统架构
森G13 天前
75、服务器源码解析---------云视频服务项目
linux·服务器·网络·c++·qt