效果展示图

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();
}