Qt—贪吃蛇项目(由0到1实现贪吃蛇项目)

用Qt实现一个贪吃蛇项目

  • 一、项目介绍
  • 二、游戏大厅界面实现
    • 2.1完成游戏大厅的背景图。
    • 2.2创建一个按钮,给它设置样式,并且可以跳转到别的页面
  • 三、难度选择界面实现
  • 四、 游戏界面实现
  • 五、在文件中写入历史战绩
    • 5.1 从文件里提取分数
    • 5.2 把贪吃蛇的长度存入文件
  • 六、总结

一、项目介绍

贪吃蛇是久负盛名的游戏,它也和俄罗斯⽅块,扫雷等游戏位列经典游戏的⾏列。 在编程语⾔的教学中,我们以贪吃蛇为例,从设计到代码实现来提升编程能⼒和逻辑能⼒。它通过控制蛇头⽅向吃⻝物,从⽽使得蛇变得越来越⻓。在本游戏中设置了上下左右四个⽅向键来控制蛇的移动⽅向。⻝物的产⽣是随机⽣成的,当蛇每吃⼀次⻝物 就会增加⼀节⾝体,同时游戏积分也会相应的加⼀。
在本游戏的设计中,蛇的⾝体会越吃越⻓,⾝体越⻓对应的难度就越⼤,因为⼀旦蛇头和⾝体相交游戏就会结束。
本项⽬使⽤ Qt 实现⼀款简单的贪吃蛇游戏。
项目的目标:

  1. 游戏大厅界面实现
  2. 难度选择界面实现
  3. 游戏界面实现
  4. 分数记录界面实现

二、游戏大厅界面实现

2.1完成游戏大厅的背景图。

1.背景图的渲染,我们通过QT的绘图事件完成

void gamehall::paintEvent(QPaintEvent *event)
{
 	 //实例化一个画家
    QPainter paint(this);
    //实例化一个设备
    QPixmap pix(":res/game_hall.png");
    //进行绘画
    paint.drawPixmap(0,0,this->width(),this->height(),pix);
 }

2.对我们的标题栏进行设置

 	//设置窗口大小
    this->setFixedSize(1000,800);
    //设置标题栏图标
    this->setWindowIcon(QIcon(":res/ico.png"));
    //设置标题栏标签
    this->setWindowTitle("游戏大厅");

在这里插入图片描述

2.2创建一个按钮,给它设置样式,并且可以跳转到别的页面

1.创建一个按钮,给它设置样式

  QFont font("华文行楷",25);
    //设置按钮
    QPushButton *intoBtn= new QPushButton(this);
    intoBtn->setFont(font);
    intoBtn->setText("开始游戏");
    intoBtn->setStyleSheet("QPushButton{border:0px;}");
    intoBtn->move(450,520);
    

2.创建的新页面
点击add new
在这里插入图片描述
3. 建立信号槽,使按钮被点击后跳转界面(这个跳转的界面,是新创建的文件,点击按钮会发出声音)

	//创建另一个窗口
    GameSelect *select=new GameSelect();
    connect(intoBtn,&QPushButton::clicked,[=]{
        //关闭上个窗口
        this->close();
        //设置窗口大小
        select->setGeometry(this->geometry());
        //显示窗口
        select->show();
        //发出声音
         QSound::play(":res/clicked.wav");

在这里插入图片描述
4.总代码

#include "gamesnake.h"
#include "ui_gamesnake.h"
#include "gameselect.h"
#include <QPainter>
#include <QPixmap>
#include <QIcon>
#include <QPushButton>
#include <QSound>
GameSnake::GameSnake(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::GameSnake)
{
    ui->setupUi(this);
    //设置窗口大小
    this->setFixedSize(1000,800);
    //设置窗口图标
    this->setWindowIcon(QIcon(":res/ico.png"));
    //设置窗口标签
    this->setWindowTitle("游戏大厅");
    //设置字体
    QFont font("华文行楷",25);
    //设置按钮
    QPushButton *intoBtn= new QPushButton(this);
    intoBtn->setFont(font);
    intoBtn->setText("开始游戏");
    intoBtn->setStyleSheet("QPushButton{border:0px;}");
    intoBtn->move(450,520);
    //创建另一个窗口
    GameSelect *select=new GameSelect();
    connect(intoBtn,&QPushButton::clicked,[=]{
        //关闭上个窗口
        this->close();

        select->setGeometry(this->geometry());
        select->show();
        QSound::play(":res/clicked.wav");



   });
}

GameSnake::~GameSnake()
{
    delete ui;
}

void GameSnake::paintEvent(QPaintEvent *event)
{
    //实例化一个画家
    QPainter paint(this);
    //实例化一个设备
    QPixmap pix(":res/game_hall.png");
    //进行绘画
    paint.drawPixmap(0,0,this->width(),this->height(),pix);
}

注意pro文件里的配置加上multimedai

三、难度选择界面实现

我们已经把贪吃蛇的游戏界面完成了,下面就进入关卡选择界面。
在关卡选择界⾯上设置了四个游戏模式按钮,分别是:容易模式、正常模式、困难模式、地狱模式;⼀个 “历史战绩” 按钮;⼀个返回游戏⼤厅界⾯的按钮。
1. 创建按钮,给它设置样式。

    //容易关卡
   QPushButton *briefnessBtn= new QPushButton(this);
   briefnessBtn->setStyleSheet("QPushButton{background-color:#0072C6;color: black; border:0px groove gray;border-radius:10px;padding:6px;}");
   briefnessBtn->move(400,200);
   QFont font("华文行楷",25);
   briefnessBtn->setFont(font);
   briefnessBtn->setText("容易模式");

如图,我已经创建了5个按钮:
在这里插入图片描述

2. 为了使第二个界面可以返回到第一个界面,创建一个按钮,按下按钮触发信号,就可以返回第一个页面。(返回按钮)

//返回按钮
QPushButton *returnBtn= new QPushButton(this);
returnBtn->move(850,700);
returnBtn->setIcon(QIcon(":res/up.png"));

connect(returnBtn,&QPushButton::clicked,[=]{
    this->close();
    GameSnake *snake= new GameSnake();
    snake->show();
    QSound::play(":res/clicked.wav");
        });

在这里插入图片描述
3. 游戏选择页面跳转到游戏大厅
实现页面之间的跳转

 //实现游戏房间和选择关卡切换
    //创建另一个窗口
    GameRoom *room=new GameRoom();


    //创建按钮,给按钮设置格式
    //容易关卡
   QPushButton *briefnessBtn= new QPushButton(this);
   briefnessBtn->setStyleSheet("QPushButton{background-color:#0072C6;color: black; border:0px groove gray;border-radius:10px;padding:6px;}");
   briefnessBtn->move(400,200);
   QFont font("华文行楷",25);
   briefnessBtn->setFont(font);
   briefnessBtn->setText("容易模式");
   connect(briefnessBtn,&QPushButton::clicked,[=]{
       //关闭上个窗口
       this->close();

       room->setGeometry(this->geometry());
       room->show();
       QSound::play(":res/clicked.wav");
  });

以第一个按钮为例,运行后点击简单模式效果如下(这是一个新的界面):
在这里插入图片描述
4. 总代码

#include "gameselect.h"
#include <QPainter>
#include <QPixmap>
#include <QPushButton>
#include "gamesnake.h"#
#include "gameroom.h"
#include <QSound>
GameSelect::GameSelect(QWidget *parent) : QWidget(parent)
{
    this->setFixedSize(1000,800);
    //设置窗口图标
    this->setWindowIcon(QIcon(":res/ico.png"));
    //设置窗口标签
    this->setWindowTitle("选择大厅");

   //实现游戏房间和选择关卡切换
    //创建另一个窗口
    GameRoom *room=new GameRoom();


    //创建按钮,给按钮设置格式
    //容易关卡
   QPushButton *briefnessBtn= new QPushButton(this);
   briefnessBtn->setStyleSheet("QPushButton{background-color:#0072C6;color: black; border:0px groove gray;border-radius:10px;padding:6px;}");
   briefnessBtn->move(400,200);
   QFont font("华文行楷",25);
   briefnessBtn->setFont(font);
   briefnessBtn->setText("容易模式");
   connect(briefnessBtn,&QPushButton::clicked,[=]{
       //关闭上个窗口
       this->close();

       room->setGeometry(this->geometry());
       room->show();
       QSound::play(":res/clicked.wav");

  });


   //正常关卡
  QPushButton *normalBtn= new QPushButton(this);
  normalBtn->setStyleSheet("QPushButton{background-color:#0072C6;color: black; border:0px groove gray;border-radius:10px;padding:6px;}");
  normalBtn->move(400,280);
  QFont font1("华文行楷",25);
  normalBtn->setFont(font);
  normalBtn->setText("正常模式");
  connect(normalBtn,&QPushButton::clicked,[=]{
      //关闭上个窗口
      this->close();

      room->setGeometry(this->geometry());
      room->show();
      QSound::play(":res/clicked.wav");

 });

  //困难关卡
 QPushButton *difficultyBtn= new QPushButton(this);
 difficultyBtn->setStyleSheet("QPushButton{background-color:#0072C6;color: black; border:0px groove gray;border-radius:10px;padding:6px;}");
 difficultyBtn->move(400,360);
 QFont font2("华文行楷",25);
 difficultyBtn->setFont(font);
 difficultyBtn->setText("困难模式");
 connect(difficultyBtn,&QPushButton::clicked,[=]{
     //关闭上个窗口
     this->close();

     room->setGeometry(this->geometry());
     room->show();
     QSound::play(":res/clicked.wav");

});

 //地狱关卡
QPushButton *bhellBtn= new QPushButton(this);
bhellBtn->setStyleSheet("QPushButton{background-color:#0072C6;color: black; border:0px groove gray;border-radius:10px;padding:6px;}");
bhellBtn->move(400,440);
QFont font3("华文行楷",25);
bhellBtn->setFont(font);
bhellBtn->setText("地狱模式");
connect(bhellBtn,&QPushButton::clicked,[=]{
    //关闭上个窗口
    this->close();

    room->setGeometry(this->geometry());
    room->show();
    QSound::play(":res/clicked.wav");

});

//排行榜
QPushButton *ranpingBtn= new QPushButton(this);
ranpingBtn->setStyleSheet("QPushButton{background-color:#0072C6;color: black; border:0px groove gray;border-radius:10px;padding:6px;}");
ranpingBtn->move(400,520);
QFont font4("华文行楷",25);
ranpingBtn->setFont(font);
ranpingBtn->setText("历史战绩");

//返回按钮
QPushButton *returnBtn= new QPushButton(this);
returnBtn->move(850,700);
returnBtn->setIcon(QIcon(":res/up.png"));

connect(returnBtn,&QPushButton::clicked,[=]{
    this->close();
    GameSnake *snake= new GameSnake();
    snake->show();
    QSound::play(":res/clicked.wav");
        });
}
void GameSelect::paintEvent(QPaintEvent *event)
{
    //设置窗口大小
    this->setFixedSize(1000,800);
    //创建绘画者
    QPainter paint(this);
    //创建画板
    QPixmap pix(":res/game_select.png");
    paint.drawPixmap(0,0,this->width(),this->height(),pix);
}

在这里插入图片描述

注意:历史战绩还没有设计

四、 游戏界面实现

前两个页面已经实现完成了,最后完成游戏界面,我们就可以玩上自己写的游戏了。

游戏房间界⾯包含下⾯⼏个部分:
• 背景图的绘制。
• 蛇的绘制、蛇的移动、判断蛇是否会撞到⾃⼰ 。
• 积分的累加和绘制 在这⾥我们要考虑⼏个⽐较核⼼的问题:

  1. 怎么让蛇动起来?
    • 我们可以⽤⼀个链表表⽰贪吃蛇,⼀个⼩⽅块表⽰蛇的⼀个节点, 我们设置蛇的默认⻓度为3。
    • 向上移动的逻辑就是在蛇的上⽅加⼊⼀个⼩⽅块, 然后把最后⼀个⼩⽅块删除即可。
    • 需要⽤到定时器Qtimer 每100 - 200ms 重新渲染。
  2. 怎么判断蛇有没有吃到⻝物?
    • 判断蛇头和⻝物的坐标是否相交,Qt 有相关的接⼝调⽤。
  3. 怎么控制蛇的移动?
    • 借助QT的实践机制实现, 重写keyPressEvent即可, 在函数中监控想要的键盘事件即可 。
    • 我们通过绘制四个按钮,使⽤信号和槽的机制控制蛇的上、下、左、右移动⽅向。

1.先要对游戏界面进行渲染,用到pixmap和painter。

void GameRoom::paintEvent(QPaintEvent *event)
{
    qDebug("开始绘画");
    //创建绘画者
    QPainter paint(this);
    //创建画板,不带有参数
    QPixmap pix;
    //load方法,加载资源或者数据
    //游戏区域
    pix.load(":res/game_room.png");
    paint.drawPixmap(0,0,800,800,pix);
    //控制区域
    pix.load(":res/bg1.png");
    paint.drawPixmap(800,0,201,900,pix);
}

2.创建一个按钮,实现页面之间的跳转

  //创建一个返回按钮
    QPushButton* returnButton = new QPushButton(this);
    //设置位置和按钮照片
    returnButton->move(900,700);
    returnButton->setIcon(QIcon(":res/up.png"));
    //创建信号槽
    connect(returnButton,&QPushButton::clicked,[=]{
    //关闭当前页面
    this->close();
    GameSelect *gameRn = new GameSelect();
    //显示上个页面
    gameRn->show();
    QSound::play(":res/clicked.wav");
    });

如图:
在这里插入图片描述
3. 对游戏房间数据结构进行封装
gameroom的头文件

#define GAMEROOM_H

#include <QWidget>
//枚举蛇的移动方向
enum class kSnakeDirect
{
    UP = 0,
    DOWN,
    LEFT,
    RIGHT
};

class GameRoom : public QWidget
{
    Q_OBJECT
public:
    explicit GameRoom(QWidget *parent = nullptr);
    //重写绘画事件
    void paintEvent(QPaintEvent *event);
private:
    //表示蛇身体结点的宽度
    const int kSnakeNodeWidth = 20;
    //表示蛇身体节点的高度
    const int kSnakeNodeHeight = 20;
    //表示蛇的速度
    const int KDefountTimeout = 100;
    //表示贪吃蛇的链表
    QList<QRectF> snakeList;
    //表示食物的结点
    QRectF foodRect;
    //表示蛇初始方向的默认值
    kSnakeDirect moveDirect = kSnakeDirect::UP;
};

4.蛇移动方向的实现

注意: 这⾥贪吃蛇不允许直接掉头, ⽐如当前是向上的, 不能直接修改为向下。

分别声明:

void moveUp();//蛇向上移动
void moveDown();//蛇向下移动
void moveLeft();//蛇向左移动
void moveRight();//蛇向右移动

在这里插入图片描述
列如蛇向上移动的定义

void GameRoom::moveUp()
{
    QPointF leftTop; // 左上⻆坐标
     QPointF rightBottom; // 右下⻆坐标
     auto snakeNode = snakeList.front();
     int headX = snakeNode.x();
     int headY = snakeNode.y();
     // 如果上⾯剩余的空间不够放⼊⼀个新的节点, 相当于到墙边了, 要处理穿墙逻辑
     if(headY-kSnakeNodeWidth < 0) {
     leftTop = QPointF(headX, this->height() - kSnakeNodeHeight);
     } else {
     leftTop = QPointF(headX, headY - kSnakeNodeHeight);
     }
     rightBottom = leftTop + QPointF(kSnakeNodeWidth, kSnakeNodeHeight);
     snakeList.push_front(QRectF(leftTop, rightBottom));
}

5.判断游戏是否结束
贪吃蛇游戏的结束标志是自己碰到自己,才算结束。

bool GameRoom::checkFail()
{
    for(int i=0;i<snakeList.size();i++)
    {
        for(int j=i+1;j<snakeList.size();j++)
        {
            if(snakeList.at(i)==snakeList.at(j))
            {
                 return true;//游戏结束
            }
        }
    }
    return false;//游戏正常运行
}

6.在绘图事件里把蛇绘画出来,并初始化贪吃蛇

 //绘制蛇:蛇头+蛇身+蛇尾
    //绘制蛇头的上下左右
    if(moveDirect==kSnakeDirect::UP)
    {
        pix.load(":res/rescopy.png");//加载资源
    }
    else if(moveDirect == kSnakeDirect::DOWN)
    {
        pix.load(":res/rescopy1.png");//加载资源
    }
    else if(moveDirect==kSnakeDirect::LEFT)
    {
        pix.load(":res/rescopy 2.png");//加载资源
    }
    else
    {
        pix.load(":res/rescopy3.png");//加载资源
    }
    //获取链表的头结点
    auto snakeHeadNode=snakeList.front();
    //画家绘画,给这个结点绘制pix里面的资源
   paint.drawPixmap(snakeHeadNode.x(),snakeHeadNode.y(),snakeHeadNode.width(),snakeHeadNode.height(),pix);

   //绘制蛇身
   pix.load(":res/rescopy 5.png");
   for(int i=1;i<snakeList.size()-1;i++)
   {
       auto node=snakeList.at(i);
       paint.drawPixmap(node.x()+2,node.y(),node.width()-3,node.height(),pix);
   }
   //绘制蛇尾
   auto TailNode = snakeList.back();
   paint.drawPixmap(TailNode.x()+2,TailNode.y(),TailNode.width()-3,TailNode.height(),pix);

在构造函数里,初始化贪吃蛇

  // 初始化贪吃蛇
     snakeList.push_back(QRectF(this->width() * 0.5, this->height() * 0.5,
    kSnakeNodeWidth, kSnakeNodeHeight));
     moveUp();
     moveUp();

7. 定义贪吃蛇的食物

//创建随机的食物
void GameRoom::creatNewFood()
{
    foodRect= QRectF(qrand()%(800/kSnakeNodeWidth)*kSnakeNodeWidth,qrand()%(800/kSnakeNodeHeight)*kSnakeNodeHeight,kSnakeNodeWidth,kSnakeNodeHeight);
}
//在绘图事件里,绘制食物
  //绘制食物
   pix.load(":res/food.bmp");
   paint.drawPixmap(foodRect.x(),foodRect.y(),foodRect.width(),foodRect.height(),pix);

8.让贪吃蛇移动起来

定时器的是为了实现每隔⼀段时间能处理移动的逻辑并且更新绘图事件。
• ⾸先, 需要判断蛇头和⻝物节点坐标是否相交 ◦ 如果相交, 需要创建新的⻝物节点, 并且需要更新蛇的⻓度, 所以 cnt 需要 +1 ;
• 如果不相交, 那么直接处理蛇的移动即可。
• 根据蛇移动⽅向 moveDirect 来处理蛇的移动, 处理⽅法是在前⽅加⼀个, 并且删除后⽅节点;
• 重新触发绘图事件, 更新渲染。

//在构造函数里编写
timer = new QTimer(this);
 connect(timer, &QTimer::timeout, this, [=](){
 int cnt = 1;
 // 判断是否贪吃蛇和⻝物是否相交
 if (snakeList.front().intersects(foodRect)) {
 createNewFood();
 ++cnt;
 //蛇吃食物的声音
 QSound::play(":res/eatfood.wav");
 }
 while(cnt--) {
 // 处理蛇的移动
 switch (moveDirect) {
 case SnakeDirect::UP:
 moveUp();
 break;
 case SnakeDirect::DOWN:
 moveDown();
 break;
 case SnakeDirect::LEFT:
 moveLeft();
 break;
 case SnakeDirect::RIGHT:
 moveRight();
 break;
 default:
 qDebug() << "⾮法移动⽅向";
 break;
 }
 }
 // 删除最后⼀个节点
 snakeList.pop_back();
 update();
 });

9.设置游戏开始和游戏暂停按钮

在刚进⼊游戏房间界⾯时,⼀定不能点击 “退出” 按钮,如果点击 “退出” 按钮,那么程 序就会异常退出。点击的顺序⼀定是:先点击 “开始” 按钮,最后才能点击 “退出” 。

    //设置开始暂停按钮
    QPushButton *startbtn = new QPushButton(this);
    QPushButton *stopbtn = new QPushButton(this);
    QFont ft("楷体", 20);
    //设置按钮的位置
    startbtn->move(860,150);
    stopbtn->move(860,200);
    //设置按钮⽂本
    startbtn->setText("开始");
    stopbtn->setText("暂停");
    //设置按钮样式
    startbtn->setStyleSheet("QPushButton{border:0px;}");
    stopbtn->setStyleSheet("QPushButton{border:0px;}");
    //设置按钮字体格式
    startbtn->setFont(ft);
    stopbtn->setFont(ft);
    //蛇移动
    connect(startbtn,&QPushButton::clicked,this,[=](){
        isGameStart = true;
        timer->start(kDefountTimeout);
        sound = new QSound(":res/Trepak.wav"); //声⾳路径
             sound->play(); //播放
             sound->setLoops(-1); //循环播放
    });
    //蛇暂停
    connect(stopbtn,&QPushButton::clicked,this,[=](){
        isGameStart = false;
        timer->stop();//停止工作
        sound->stop();//停止播放
    });

10. 设置蛇的方向控制

 //设置蛇2的移动方向
    QPushButton *Up = new QPushButton(this);
    QPushButton *Down = new QPushButton(this);
    QPushButton *Left = new QPushButton(this);
    QPushButton *Right = new QPushButton(this);
    Up->move(880,400);
    Down->move(880,480);
    Left->move(840,440);
    Right->move(920,440);
    Up->setStyleSheet("QPushButton{border:0px;}");
    Up->setFont(font);
    Up->setText("↑");
    Down->setStyleSheet("QPushButton{border:0px;}");
    Down->setFont(font);
    Down->setText("↓");
    Left->setStyleSheet("QPushButton{border:0px;}");
    Left->setFont(font);
    Left->setText("←");
    Right->setStyleSheet("QPushButton{border:0px;}");
    Right->setFont(font);
    Right->setText("→");
    connect(Up,&QPushButton::clicked,this,[=](){
        if(moveDirect != kSnakeDirect::DOWN)
            moveDirect = kSnakeDirect::UP;
    });
    connect(Down,&QPushButton::clicked,this,[=](){
        if(moveDirect != kSnakeDirect::UP)
            moveDirect = kSnakeDirect::DOWN;
    });
    connect(Left,&QPushButton::clicked,this,[=](){
        if(moveDirect != kSnakeDirect::RIGHT)
            moveDirect = kSnakeDirect::LEFT;
    });
    connect(Right,&QPushButton::clicked,this,[=](){
        if(moveDirect != kSnakeDirect::LEFT)
            moveDirect = kSnakeDirect::RIGHT;
        });

我们也可以用键盘来控制蛇的方向

void GameRoom::keyPressEvent(QKeyEvent *event)
{
    switch (event->key()) {
    case Qt::Key_W :
    case Qt::Key_Up :
        if(moveDirect != kSnakeDirect::DOWN)
        moveDirect = kSnakeDirect::UP;
        break;
    case Qt::Key_S :
    case Qt::Key_Down :
        if(moveDirect != kSnakeDirect::UP)
        moveDirect=kSnakeDirect::DOWN;
        break;
    case Qt::Key_D :
    case Qt::Key_Right :
        if(moveDirect != kSnakeDirect::LEFT)
        moveDirect=kSnakeDirect::RIGHT;
        break;
    case Qt::Key_A :
    case Qt::Key_Left :
        if(moveDirect != kSnakeDirect::RIGHT)
        moveDirect=kSnakeDirect::LEFT;
        break;
        //开始
     case Qt::Key_F :
        isGameStart = true;
        timer->start(moveDefount);
        sound = new QSound(":res/Trepak.wav"); //声⾳路S径
        sound->play(); //播放
        sound->setLoops(-1); //循环播放
        break;
//      //暂停
     case Qt::Key_G :
        isGameStart = false;
        timer->stop();//停止工作
        sound->stop();//停止播放
        break;
    }
}

11.设置游戏退出按钮,并设置一个消息盒子。

    //设置退出按钮,并给他设置样式
    QPushButton *exitBtn=new QPushButton(this);
    exitBtn->setText("退出");
    exitBtn->move(870,750);
    exitBtn->setFont(font);
    //设置消息盒子
    QMessageBox *msg=new QMessageBox(this);
    QPushButton *okBtn =new QPushButton("OK");
    QPushButton *cancelBtn =new QPushButton("cancel");
    msg->addButton(okBtn,QMessageBox::AcceptRole);
    msg->addButton(cancelBtn,QMessageBox::RejectRole);
    msg->setWindowTitle("退出游戏");
    msg->setText("确认退出游戏吗?");
    connect(exitBtn,&QPushButton::clicked,[=]{
        //显示消息盒子
        msg->show();
         QSound::play(":res/clicked.wav");
        //事件轮询
        msg->exec();
        if(msg->clickedButton()==okBtn)
        {
            this->close();//关闭程序
        }
        else
        {
            msg->close();//关闭信息盒子
        }
    });

12. 分数的绘制

 //绘制分数
   pix.load(":res/sorce_bg.png");
   paint.drawPixmap(this->width()*0.85,this->height()*0.06,90,40,pix);
   QPen pen;
   pen.setColor(Qt::black);
   QFont font("方正舒体",22);
   paint.setPen(pen);
   paint.setFont(font);
   paint.drawText(this->width()*0.9,this->height()*0.1,QString("%1").arg(snakeList.size()));

13.游戏失败的绘制

   //绘制游戏失败效果
   if(checkFail())
   {
       pen.setColor(Qt::red);
       paint.setPen(pen);
       QFont font("方正舒体",50);
       paint.setFont(font);
       paint.drawText(this->width()*0.25,this->height()*0.5,QString("GAME OVER!"));
       timer->stop();
       QSound::play((":res/gameover.wav"));
       sound->stop();
   }

在这里插入图片描述
14.实现4种不同游戏模式
在这里插入图片描述
先对各个模式的时间进行设置,然后设置房间的定时器时间,从而改变游戏的模式。

room->setTimer(200);//改变各个模式的速度默认值

通过默认值去改变时间,从而设置游戏模式

在这里插入图片描述

五、在文件中写入历史战绩

通过文件的方式用来显示历史战绩

5.1 从文件里提取分数

读⽂件:读取写⼊⽂件中蛇的⻓度

connect(ranpingBtn,&QPushButton::clicked,[=]{
    //创建一个窗口控件
    QWidget *wGet=new QWidget();
    wGet->setWindowTitle("历史战绩");
    wGet->setFixedSize(500,300);
    //创建一个多行输入框
    QTextEdit *edit=new QTextEdit(wGet);

    edit->setFont(font);
    edit->setFixedSize(500,300);
    //打开文件,并且只能读,文件要自己创建
    QFile file("D:/QT_creator_3_25/greedy_snake1/Snake/res/1.txt");
    file.open(QIODevice::ReadOnly);
    //文本流对象
    QTextStream in(&file);
    //in.表示文件,把文件里的数据按行读取,并且转化为整数
    int data=in.readLine().toInt();
     edit->append("得分为:");
    //这里需要的是QString类型,把整形转化为字符串
    edit->append(QString::number(data));
    //显示窗口
    wGet->show();
    QSound::play(":res/clicked.wav");
    file.close();
});

在这里插入图片描述

5.2 把贪吃蛇的长度存入文件

写⽂件:往⽂件中写⼊蛇的⻓度

 //把分数存入文件
   int c=snakeList.size();
   QFile file("D:/QT_creator_3_25/greedy_snake1/Snake/res/1.txt");
   if(file.open(QIODevice::Text|QIODevice::WriteOnly))
   {
       //输入文本和只写
   QTextStream out(&file);
   out<<c;
       //关闭文件
    file.close();
   }

在这里插入图片描述
在这里插入图片描述

最后通过黑盒测试的方法,解决程序的一些问题,确保程序正常运行。(解决了按左右键,游戏就失败的问题;解决了蛇不在窗口跑的问题)

六、总结

做完这个项目,收获非常大。对qt代码的理解也更加深刻,同时也了解了一点额外的知识点
注意:

  1. QPixmap中的load函数是将图片加载到缓冲区,即QPixmapCache中存放图片,当把第一张图片加载到缓冲区会显示图片1,当加载第二张图片时缓冲区的图片1并没有被覆盖,实际是缓冲区存了两张图片,并显示图片2,当再次加载图片1到缓冲区时,这时QPixmapCache认为已经有了图片1,会直接返回true,缓冲区的图片排列顺序并没有发生变化,固依旧显示图片2。
    解决办法:
    (1)QPixmap直接定义局部变量,这样每次会开辟新的缓冲区
    (2)每次加载图片时先清空缓冲区,调用QPixmapCache::clear()
  2. QPointF就是Float QPoint,用法的话QPointF在浮点精度上表示平面上的点,绝大部分操作都是与QPoint相类似的,细微的差别在于运算符重载以及提供了QPoint与QPointF的相互转换。
  3. 在Qt中QList和QVector一般获取元素都是通过 at(index) 来获取得,但是at获取的元素返回值是一个const & 常引用,也就是元素不支持改变。
  4. snakeList.front().intersects(foodRect),判断两个矩形会不会相交。
  5. QTextStream文本流对象
    QTextStream out(&文件指针)
    QTextStream in(&文件指针)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/753626.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何断点调试opencv源码

分几个步骤&#xff1a; 1、下载opencv-4.10.0-windows.exe https://opencv.org/releases/ 2、想要调试opencv的源码&#xff0c;只需要将这两个文件拷贝到我们自己项目的可执行文件的同级目录内即可。 完成拷贝后&#xff0c;直接在vs工程中打断点F11进行单步调试&#xff…

ASP.NET MVC-简单例子-配置日志文件-log4net

环境&#xff1a; win10&#xff0c;SQL Server 2008 R2 安装 使用NuGet 安装时发现报错并无法安装&#xff1a; 现有 packages.config 文件中检测到一个或多个未解析包依赖项约束。必须解析所有依赖项约束以添加或更新包。如果正在更新这些包&#xff0c;则可忽略此消息&am…

2024-6-28 石群电路-32

2024-6-28&#xff0c;星期五&#xff0c;20:05&#xff0c;天气&#xff1a;雨&#xff0c;心情&#xff1a;晴。今天没有什么事情发生&#xff0c;继续学习&#xff0c;加油&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 1. 对称三相电路的计算&#xff08…

算法基础--------【图论】

图论&#xff08;待完善&#xff09; DFS:和回溯差不多 BFS:进while进行层序遍历 定义: 图论&#xff08;Graph Theory&#xff09;是研究图及其相关问题的数学理论。图由节点&#xff08;顶点&#xff09;和连接这些节点的边组成。图论的研究范围广泛&#xff0c;涉及路径、…

学习笔记——动态路由——OSPF(OSPF协议的工作原理)

八、OSPF协议的工作原理 1、原理概要 (1)相邻路由器之间周期性发送HELLO报文&#xff0c;以便建立和维护邻居关系 (2)建立邻居关系后&#xff0c;给邻居路由器发送数据库描述报文(DBD)&#xff0c;也就是将自己链路状态数据库中的所有链路状态项目的摘要信息发送给邻居路由器…

【PHP项目实战训练】——后台-RBAC权限管理原理

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

Minecraft玩家设计专用程序 让Google地球可以在游戏中探索

在 Minecraft 中以真实的比例建造真实的地方并不是什么新鲜事。不过&#xff0c;康奈尔理工学院的一名毕业生最近展示了一种方法&#xff0c;可以自动生成一个忠实的 Minecraft 地球&#xff0c;并定期更新。他将在 7 月底举行的 SIGGRAPH 2024 大会上公布该项目的成果。 在七月…

确认偏差:金融市场交易中的隐形障碍

确认偏差&#xff0c;作为一种深刻影响交易员决策与表现的心理现象&#xff0c;其核心在于个体倾向于寻求与既有信念相符的信息&#xff0c;而自动过滤或轻视与之相悖的资讯。这种认知偏见严重扭曲了交易者的决策过程&#xff0c;导致他们过分依赖符合既有观念的数据&#xff0…

鸿蒙开发设备管理:【@ohos.deviceInfo (设备信息)】

设备信息 说明&#xff1a; 本模块首批接口从API version 6开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 导入模块 import deviceInfo from ohos.deviceInfo属性 系统能力&#xff1a;以下各项对应的系统能力均为SystemCapability.Startup.S…

构建一个让世界瞩目的海外短剧生态系统

构建一个让世界瞩目的海外短剧生态系统是一个复杂但富有挑战性的任务。旨在创建一个全球范围内具有影响力的海外短剧生态系统&#xff1a; 一、市场定位与战略规划 1、深入了解目标市场&#xff1a;研究海外观众的观看习惯、喜好和付费意愿&#xff0c;以制定有针对性的市场策…

3d模型里地毯的材质怎么赋予?---模大狮模型网

在进行3D建模时&#xff0c;赋予地毯逼真的材质是营造现实感和增强场景氛围的重要步骤。模大狮将介绍在常见的3D建模软件中&#xff0c;如何有效地为地毯赋予各种材质&#xff0c;以及一些实用的技巧和注意事项。 一、选择合适的地毯材质 在3D建模中&#xff0c;地毯的材质选择…

OOXML入门学习

进入-飞入 <par> <!-- 这是一个并行动画序列的开始。"par"代表并行&#xff0c;意味着在这个标签内的所有动画将同时开始。 --><cTn id"5" presetID"2" presetClass"entr" presetSubtype"4" fill"hold&…

MS5208T/MS5208N——2.7V 到 5.5V、 12Bit、8 通道轨到轨输出数模转换器

MS5208T/MS5208N 是一款 12Bit 、 8 通道输出的电压型 DAC &#xff0c;内部集成上电复位电路、轨到轨输出 Buffer 。接口采用 三线串口模式&#xff0c;最高工作频率可以到 40MHz &#xff0c;兼容 SPI 、 QSPI 、 DSP 接口和 Microwire 串口。输出接到一个轨到轨…

“AI+”时代,群核科技进化成了家居设计打工人理想的样子

6月&#xff0c;2024世界智能产业博览会上&#xff0c;人工智能大模型展团以“AI大模型驱动新质生产力”为主题&#xff0c;各家企业纷纷提到了基于不同行业场景的应用。 这透露出当前的行业发展趋势强调大模型落地核心行业&#xff0c;产生业务价值。其中&#xff0c;“AI图像…

餐饮点餐的简单MySQL集合

ER图 模型图&#xff08;没有进行排序&#xff0c;混乱&#xff09; DDL和DML /* Navicat MySQL Data TransferSource Server : Mylink Source Server Version : 50726 Source Host : localhost:3306 Source Database : schooldbTarget Server Type …

uniapp 使用cavans 生成海报

uniapp 使用cavans 生成海报 npm install qs-canvas1.创建 useCanvas.js /*** Shopro qs-canvas 绘制海报* version 1.0.0* author lidongtony* param {Object} options - 海报参数* param {Object} vm - 自定义组件实例*/ import QSCanvas from qs-canvas; import { getPos…

最小生成树拓展应用

文章目录 最小生成树拓展应用理论基础 题单1. [新的开始](https://www.acwing.com/problem/content/1148/)2. [北极通讯网络](https://www.acwing.com/problem/content/1147/)3. [走廊泼水节](https://www.acwing.com/problem/content/348/)4. [秘密的牛奶运输](https://www.ac…

Verystar费芮荣获腾讯游戏人生平台2023年度“最佳营销服务商”奖项

先导&#xff1a;Verystar费芮是电通旗下拥有领先的技术支持、数据驱动的客户体验管理 (CXM) 公司&#xff0c; 6月27日腾讯游戏人生合作伙伴大会&#xff0c;宣布 Verystar费芮连续四年荣获“最佳营销服务商”奖项。 6月27日&#xff0c;2024年腾讯游戏人生合作伙伴大会在深圳…

【知识图谱系列】Neo4j使用Py2neo与python进行链接

目录 一、安装py2neo 二、打开Neo4j 三、使用Python操作Neo4j 一、安装py2neo pip install --upgrade py2neo -i https://pypi.tuna.tsinghua.edu.cn/simple 可以先阅读下文档&#xff1a;https://py2neo.org/v4/index.html 这个文档里有好多关于这个工具包的API介绍&#x…

从赛题切入谈如何学习数学建模

1.引言 &#xff08;1&#xff09;今天学习了这个汪教授的这个视频&#xff0c;主要是对于一个赛题的介绍讲解&#xff0c;带领我们通过这个赛题知道数学建模应该学习哪些技能&#xff0c;以及这个相关的经验&#xff0c;我感觉这个还是让我自己受益匪浅的 &#xff08;2&…