Qt编写贪吃蛇小游戏完整项目

news2024/9/27 6:44:16

文章目录

  • 前言
  • 一、Qt环境准备
  • 二、编写思路
  • 三、编写代码
    • 1、开始游戏界面代码
      • 1.1、绘制界面
      • 1.2、界面基本配置
    • 2、选择难度界面代码
    • 3、游戏房间界面制作
      • 3.1、界面基础配置
      • 3.2、提前配置类中的成员变量
        • 3.2.1、QRectF
      • 3.3、检测游戏是否结束的方法
      • 3.4、蛇移动的实现
        • 3.4.1、蛇向上移动
        • 3.4.2、蛇向下移动
        • 3.4.3、蛇向左移动
        • 3.4.4、蛇向右移动
      • 3.5、渲染出贪吃蛇
      • 3.6、初始化贪吃蛇、绘制食物
      • 3.7、实现游戏开始与暂停(设置定时器)
      • 3.8、实现游戏控制蛇移动
      • 3.9、退出游戏按钮
      • 3.10、渲染积分、绘制结束游戏
      • 3.11、写入、获取分数
  • 四、完整代码块
    • 1、游戏主页面
      • 1.1、gamepage.h
      • 1.2、gamepage.cpp
    • 2、游戏难度选择
      • 2.1、gameselect.h
      • 2.2、gameselect.cpp
    • 3、游戏房间界面
      • 3.1、gameroom.h
      • 3.2、gameroom.cpp
  • 总结


前言

  该文章是记录用Qt编写贪吃蛇小游戏项目的步骤也方法注意事项,且本次使用Markdown编辑器编辑文章。


一、Qt环境准备

我们编写项目环境是必不可少的,未来我会准备一章编写教大家如何去配置Qt环境的。

二、编写思路

我们可以先编写一个给玩家开始游戏选择的界面,例如:
在这里插入图片描述
选择开始游戏之后,我们界面可以变为选择难度,例如:
在这里插入图片描述
选择难度之后我们就可以跳转到游戏界面了,游戏界面如下:
在这里插入图片描述
接下来我们开始编写代码。

三、编写代码

1、开始游戏界面代码

1.1、绘制界面

  在编写界面时我们要先创建好类,我们暂且先称为GamePage吧,在Qt中插入图片的方法有多种,但是一般我们不会在QWidget中的构造函数中编写,而是要放到重写的paintEvent方法中,其方法的作用在于界面发生任何改变时、窗口最小化时,就会主动调用repaint()或者update()方法使图片不会看不见。
  我们Qt中提供了绘画的API接口使用QPainter类去绘画,绘制照片时需使用QPixmap,QPixmap主要是用来在屏幕上显示图形,且Qt对该类在屏幕上进行了特别的优化。
代码如下:

注意:painter的drawPixmap方法使用(绘制的位置x、y坐标,绘制长宽width、height,最后选项是用哪个pixmap类

void GamePage::paintEvent(QPaintEvent *event)
{
    (void)event;
    QPainter painter(this);
    QPixmap pix(":/src source/interface.jpg");
    painter.drawPixmap(0,0,this->width(),this->height(),pix);
}

  可能会有人会疑问,为什么这个路径是这样的?其实这里是使用了Qt中qrc文件, qrc ⽂件是⼀种XML格式的资源配置⽂件,我们运用此文件可以通过将资源⽂件添加到项⽬中来⽅便地访问和管理这些资源。方法如下:
在这里插入图片描述
这里无脑下一步,接下来添加路径,路径自行修改,添加文件即可:
在这里插入图片描述
在这里插入图片描述

1.2、界面基本配置

准备了绘制方法后,我们就可以设置界面窗口的基础设置了。
我们可以先设置好窗口的固定大小,使用 setFixedSize 方法去调整。
修改窗口图标与标题、添加按钮(修改好位置、设置字体格式与大小、利用QSS对按钮样式进行修改)、最后用connect对按钮信号与槽进行连接,我们可以使用你lambda表达式进行编写。
代码如下:

GamePage::GamePage(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::GamePage)
{
    ui->setupUi(this);

    //设置窗口固定大小
    this->setFixedSize(1000,700);
    //设置图标
    this->setWindowIcon(QIcon(":/src source/snake.png"));
    this->setWindowTitle("贪吃蛇游戏");

    //添加按钮
    QPushButton *start = new QPushButton(this);
    //移动按钮位置
    start->setObjectName("start");
    start->move(400,500);
    start->setText("开始游戏");
    //设置字体和大小
    start->setFont(QFont("宋体",25));
    //利用QSS去修改按钮样式
    this->setStyleSheet("#start{"
                        "border: 0px;"
                        "border-radius: 30px;"
                        "background-color: #dadbde;"
                        "padding:20px;}"
                        "#start:hover{"
                        "border: 2px solid #8f8f91}"
                        "#start:pressed {"
                        "background-color: #f6f7fa;};");
    connect(start,&QPushButton::clicked,[=]{
        GameSelect *gameSelect = new GameSelect();
        gameSelect->setGeometry(this->geometry());
        this->close();
        QSound::play(":/src source/tip_music.wav");

        gameSelect->show();

    });
}

代码中我们添加了触发按钮就会触发提示音效,使用QSound类中的play方法,当我们点击了按钮开始游戏,GamePage类界面就可以关闭了,我们就创建好GameSelect类并且显示出来。

2、选择难度界面代码

  我们在编写GameSelect界面时,思路大致与GamePage界面相似,也是先重写PaintEvent方法,绘制背景画面,在构造方法中我们要准备4个按钮给玩家选择,分别是简单难度、普通难度、困难难度以及上局分数(上局分数该按钮方法我们后面在实现),我们这里在提供一个返回按钮,让玩家可以返回到上一个GamePage界面中。

设置返回按钮…

//设置一个返回的按钮
    QPushButton *backBtn = new QPushButton(this);
    backBtn->setObjectName("backBrn");
    backBtn->setIcon(QIcon(":/src source/return.png"));
    backBtn->setStyleSheet("#backBrn{border: 1px solid #8f8f91; padding: 10px;background-color:#e1ffff;}"
                           "#backBrn:hover{border: 2px solid #ff0000;}");
    backBtn->move(this->geometry().width()-200,this->geometry().height()-180);
    connect(backBtn,&QPushButton::clicked,[=]{
       this->close();
       GamePage *gamePage = new GamePage;
       gamePage->show();
       QSound::play(":/src source/tip_music.wav");
    });

GameSelect界面代码如下:

GameSelect::GameSelect(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::GameSelect)
{
    ui->setupUi(this);

    //设置窗口固定大小
    this->setFixedSize(1000,700);
    //设置图标
    this->setWindowIcon(QIcon(":/src source/snake.png"));
    this->setWindowTitle("游戏关卡选择");

    //设置一个返回的按钮
    QPushButton *backBtn = new QPushButton(this);
    backBtn->setObjectName("backBrn");
    backBtn->setIcon(QIcon(":/src source/return.png"));
    backBtn->setStyleSheet("#backBrn{border: 1px solid #8f8f91; padding: 10px;background-color:#e1ffff;}"
                           "#backBrn:hover{border: 2px solid #ff0000;}");
    backBtn->move(this->geometry().width()-200,this->geometry().height()-180);
    connect(backBtn,&QPushButton::clicked,[=]{
       this->close();
       GamePage *gamePage = new GamePage;
       gamePage->show();
       QSound::play(":/src source/tip_music.wav");
    });

    //创建游戏房间界面
    GameRoom *gRoom = new GameRoom();


    //设置按钮的属性
    QFont font("宋体",25);
    QString style("QPushButton{"
                  "border: 0px;"
                  "border-radius: 30px;"
                  "background-color: #dadbde;"
                  "padding:20px;}"
                  "QPushButton:hover{"
                  "border: 2px solid #8f8f91}"
                  "QPushButton:pressed {"
                  "background-color: #f6f7fa;};");
    QPushButton *simpleBut = new QPushButton(this);
    simpleBut->move(390,120);
    simpleBut->setText("简单模式");
    simpleBut->setFont(font);
    simpleBut->setStyleSheet(style);
    connect(simpleBut,&QPushButton::clicked,[=]{
        this->close();
        gRoom->setGeometry(this->geometry());
        QSound::play(":/src source/tip_music.wav");
        gRoom->show();
    });


    QPushButton *normalBut = new QPushButton(this);
    normalBut->move(390,240);
    normalBut->setText("普通模式");
    normalBut->setFont(font);
    normalBut->setStyleSheet(style);
    connect(normalBut,&QPushButton::clicked,[=]{
        this->close();
        gRoom->setGeometry(this->geometry());
        QSound::play(":/src source/tip_music.wav");
        gRoom->show();
    });

    QPushButton *hardBut = new QPushButton(this);
    hardBut->move(390,360);
    hardBut->setText("困难模式");
    hardBut->setFont(font);
    hardBut->setStyleSheet(style);
    connect(hardBut,&QPushButton::clicked,[=]{
        this->close();
        gRoom->setGeometry(this->geometry());
        QSound::play(":/src source/tip_music.wav");
        gRoom->show();
    });

    QPushButton *hisBut = new QPushButton(this);
    hisBut->move(390,480);
    hisBut->setText("历史战绩");
    hisBut->setFont(font);
    hisBut->setStyleSheet(style);
}

void GameSelect::paintEvent(QPaintEvent *event)
{
    (void)event;
    QPainter painter(this);
    QPixmap pix(":/src source/game_select.png");
    painter.drawPixmap(0,0,this->width(),this->height(),pix);
}

大致编写与GamePage界面相似,按钮也使用QSS对外观进行美观制作。

3、游戏房间界面制作

3.1、界面基础配置

  设置界面配置大致与上两个界面相同这里不再赘述,至于想怎么编写都是可以的。

3.2、提前配置类中的成员变量

  在准备编写成员变量时,我们可以先提前准备好代表蛇移动方向的枚举,以便后续代码的编写与维护。

//表示蛇移动的方向
enum class SnakeDirect{
    UP = 0,
    DOWN,
    LEFT,
    RIGHT
};

  在编写类时可以先提前准备好蛇的高度与宽度以及蛇的默认移动速度,这些提前配置好,后续我们编写的时候就会方便很多,提前创建好表示贪吃蛇的链表,链表我们使用QRectF去存储,以及用QRectF类型去表示食物的节点,这里QRectF是什么类型呢?

3.2.1、QRectF

QRectF 类是Qt框架中的一个功能强大的工具,专门用于处理和操作浮点精度的矩形区域。

我们回到刚刚的话题,接下来我们要准备表示蛇移动方向的变量,我们可以暂时初始化为 SnakeDirect::UP 也就是代表向上,还要准备定时器QTimer成员变量以及代表游戏是否开始的成员变量。

onst int kSnakeNodeWidth = 20; //表示蛇身体节点的宽度
    const int kSnakeNodeHeight = 20;//表示蛇身体节点的高度
    const int kDefaultTimeout = 200;//表示蛇默认移动速度

    QList<QRectF> snakeList;//表示贪吃蛇链表
    QRectF foodRect;//表示食物节点

    SnakeDirect moveDirect = SnakeDirect::UP;//表示蛇默认移动方向
    QTimer *timer;//定时器

    bool isGameStart = false;//表示是否开始游戏

3.3、检测游戏是否结束的方法

检测游戏是否结束可以直接判断链表中是否存在元素相同,当出现相同时代表蛇头对蛇身体发生了碰撞,这样利用代码即可判断是否结束游戏。

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

3.4、蛇移动的实现

3.4.1、蛇向上移动

  当需要对蛇进行移动时,我们需要考虑当蛇穿过边缘时,蛇需要从对面的边框出现,此时我们需要用两个变量去记录矩形框左上角以及右下角的位置,
先记录蛇头的坐标位置,leftTop = QPointF(headX,this->height() - kSnakeNodeHeight); 我们可以用以上代码去控制当蛇穿过上边缘时,就会从下边框出现,其他情况正常设计即可,右下角位置就是左上角加上蛇的长与宽即可,准备好之后直接头插进蛇的链表中。

代码如下:

void GameRoom::moveUp()
{
    QPointF leftTop;    //左上角坐标
    QPointF rightBottom;//右下角坐标

    auto snakeNode = snakeList.front();//蛇头
    int headX = snakeNode.x();
    int headY = snakeNode.y();

    if(headY < 0){
        leftTop = QPointF(headX,this->height() - kSnakeNodeHeight);
    }
    else{
        leftTop = QPointF(headX,headY - kSnakeNodeHeight);
    }

    rightBottom = leftTop + QPointF(kSnakeNodeWidth,kSnakeNodeHeight);

    snakeList.push_front(QRectF(leftTop,rightBottom));
}
3.4.2、蛇向下移动

  蛇向下移动与向上移动大致相识,但是我们可以使用QPointF中的一个方法 bottomLeft() 此方法是可以获取矩形左下角的坐标,这样蛇正常向下移动时,我们可以获取矩形框的左下角坐标,将左下角的坐标赋值给左上角变量中,这样可以快捷编写代码。

void GameRoom::moveDown()
{
    QPointF leftTop;    //左上角坐标
    QPointF rightBottom;//右下角坐标

    auto snakeNode = snakeList.front();//蛇头
    int headX = snakeNode.x();
    int headY = snakeNode.y();

    if(headY > this->height()){
        leftTop = QPointF(headX,0);
    }
    else{
        leftTop = snakeNode.bottomLeft();//获取矩形左下角的坐标
    }

    rightBottom = leftTop + QPointF(kSnakeNodeWidth,kSnakeNodeHeight);

    snakeList.push_front(QRectF(leftTop,rightBottom));
}
3.4.3、蛇向左移动

方法大致与上面两个编写方法一致,就是要注意穿过墙的时候要控制好。

void GameRoom::moveLeft()
{
    QPointF leftTop;    //左上角坐标
    QPointF rightBottom;//右下角坐标

    auto snakeNode = snakeList.front();//蛇头
    int headX = snakeNode.x();
    int headY = snakeNode.y();

    if(headX < 0){
        leftTop = QPointF(700 - kSnakeNodeWidth,headY);
    }
    else{
        leftTop = QPointF(headX - kSnakeNodeWidth,headY);
    }

    rightBottom = leftTop + QPointF(kSnakeNodeWidth,kSnakeNodeHeight);

    snakeList.push_front(QRectF(leftTop,rightBottom));
}
3.4.4、蛇向右移动

这里可以利用 topRight() 获取右上角坐标

void GameRoom::moveRight()
{
    QPointF leftTop;    //左上角坐标
    QPointF rightBottom;//右下角坐标

    auto snakeNode = snakeList.front();//蛇头
    int headX = snakeNode.x();
    int headY = snakeNode.y();

    if(headX > 700){
        leftTop = QPointF(0,headY);
    }
    else{
        leftTop = snakeNode.topRight();//获取矩形右上角坐标
    }

    rightBottom = leftTop + QPointF(kSnakeNodeWidth,kSnakeNodeHeight);

    snakeList.push_front(QRectF(leftTop,rightBottom));
}

3.5、渲染出贪吃蛇

  绘制贪吃蛇我们需要分三个部分,蛇头、蛇身、蛇尾,绘制也是使用Qpainter以及QPixmap配合使用,这边不在赘述,蛇头即是之前提前编写的蛇链表(snakeList),获取蛇头的坐标位置,直接绘制, 但需要注意蛇头方向,先前准备了moveDirect表示蛇移动的方向,需要判断蛇的方向去绘制蛇头的方向 ,蛇身就需要使用循环把剩下的节点绘制出来,剩下蛇尾也是直接获取节点坐标绘制。

  //绘制蛇 蛇头 + 蛇身体 + 蛇尾巴
    //绘制蛇头:上 下 左 右
    if(moveDirect == SnakeDirect::UP){
        pix.load(":/src source/head_up.png");
    }
    else if(moveDirect == SnakeDirect::DOWN){
        pix.load(":/src source/head_down.png");
    }
    else if(moveDirect == SnakeDirect::LEFT){
        pix.load(":/src source/head_left.png");
    }
    else if(moveDirect == SnakeDirect::RIGHT){
        pix.load(":/src source/head_right.png");
    }

    auto snakeHead = snakeList.front();
    painter.drawPixmap(snakeHead.x(),snakeHead.y(),snakeHead.width(),snakeHead.height(),pix);

    //绘制蛇身
    pix.load(":/src source/body.png");
    for (int i = 1; i < snakeList.size() - 1; i++) {
        auto node = snakeList.at(i);
        painter.drawPixmap(node.x(),node.y(),node.width(),node.height(),pix);
    }

    //绘制蛇尾
    auto snakeTail = snakeList.back();
    painter.drawPixmap(snakeTail.x(),snakeTail.y(),snakeTail.width(),snakeTail.height(),pix);

3.6、初始化贪吃蛇、绘制食物

  初始化贪吃蛇我们需要在构造函数中做好准备,对链表做尾插个节点即可,此时运行程序发现就一个蛇头,那么我们可以提供多两个蛇向上移动,添加多两个节点,蛇就变成许多了。
代码如下:

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

  绘制食物可以使用 qrand 随机数让食物随机生成,不过需要注意控制好,不要让食物跑出界面之外,所以要控制好。

void GameRoom::createNewFood()
{
    foodRect = QRectF(qrand() % (750 / kSnakeNodeWidth) * kSnakeNodeWidth,
                      qrand() % (this->height() / kSnakeNodeHeight) * kSnakeNodeHeight,
                      kSnakeNodeWidth, kSnakeNodeHeight);
}

3.7、实现游戏开始与暂停(设置定时器)

  当需要蛇持续进行移动,我们就需要利用定时器让界面移动(QTimer),这里使用connect让信号与槽连接起来,在QRectF中存在一种方法 intersects 该方法作用在于判断两个矩形框是否发生相交,当我们蛇与食物发生碰撞时,让蛇链表尾插一个节点,并且让蛇持续往蛇头方向移动,还需要使用 update() 刷新链表数据,以防吃了食物蛇数据没有发生改变。
  在添加两个按钮去控制开始或者停止,开始前设置好定时器触发时间,用方法staart()启动即可,也可以准备好背景音乐QSound,Qsound中存在一个方法 setLoops 当为真时会循环播放音乐。
代码如下:

 //使用定时器
    timer = new QTimer(this);

    connect(timer,&QTimer::timeout,[=]{
        int cnt = 1;
        if(snakeList.front().intersects(foodRect)){//intersects方法作用是判断两个矩形框是否有相交
            createNewFood();
            cnt++;
            QSound::play(":/src source/succ.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;
            }
        }

        snakeList.pop_back();
        update();//用于刷新链表
    });
    QPushButton *start = new QPushButton("开始",this);
    QPushButton *stop = new QPushButton("停止",this);

    start->setObjectName("start");
    stop->setObjectName("stop");

    QFont font("宋体",10);
    start->setFont(font);
    stop->setFont(font);

    start->move(820,180);
    stop->move(820,240);

    connect(start,&QPushButton::clicked,[=]{
        if(!isGameStart){
            isGameStart = true;
            timer->start(moveTimeout);//设置定时器触发时间
            sound = new QSound(":/src source/bgm.wav",this);
            sound->play();
            sound->setLoops(-1);
        }
    });
    connect(stop,&QPushButton::clicked,[=]{
        if(isGameStart){
            isGameStart = false;
            timer->stop();
            sound->stop();
        }
    });

3.8、实现游戏控制蛇移动

  这里添加蛇移动的按钮,要配置好按钮的基础设置,也可以配置好照片,这里我设置了按钮快捷键setShortcut(),setShortcut里传的参数是QKeySequence,需注意。
代码如下:

//方向控制
    QPushButton *up = new QPushButton(QIcon(":/src source/up.png"),"上",this);
    QPushButton *down = new QPushButton(QIcon(":/src source/down.png"),"下",this);
    QPushButton *left = new QPushButton(QIcon(":/src source/left.png"),"左",this);
    QPushButton *right = new QPushButton(QIcon(":/src source/right.png"),"右",this);

    up->move(840,400);
    down->move(840,480);
    left->move(780,440);
    right->move(880,440);

    connect(up,&QPushButton::clicked,[=]{
        if(moveDirect != SnakeDirect::DOWN)
            moveDirect = SnakeDirect::UP;
    });
    connect(down,&QPushButton::clicked,[=]{
        if(moveDirect != SnakeDirect::UP    )
            moveDirect = SnakeDirect::DOWN;
    });
    connect(left,&QPushButton::clicked,[=]{
        if(moveDirect != SnakeDirect::RIGHT)
            moveDirect = SnakeDirect::LEFT;
    });
    connect(right,&QPushButton::clicked,[=]{
        if(moveDirect != SnakeDirect::LEFT)
            moveDirect = SnakeDirect::RIGHT;
    });

    up->setShortcut(QKeySequence("Up"));
    down->setShortcut(QKeySequence("Down"));
    left->setShortcut(QKeySequence("Left"));
    right->setShortcut(QKeySequence("Right"));

    start->setShortcut((QKeySequence("Space")));

3.9、退出游戏按钮

  创建退出游戏按钮并不复杂,这边主要讲的是触发按钮后弹出的界面,Qt中有QWidget还有QDialog类,Qt也提供了一些QDialog控件给程序员使用,这边我们使用QMessageBox,当触发按钮显示提示窗口,提示是否退出,所以要体用两个按钮给提示窗口了,这里需要注意按钮哪种枚举值,用于表示消息框中的接受按钮的角色,QMessageBox::AcceptRole 通常用于设置消息框的默认接受按钮(通常是“确定”或“是”按钮)。后面我们点击按钮时可使用QMessageBox中的clickedButton方法去判断即可。

//退出游戏
    QPushButton *exitBtn = new QPushButton("退出",this);
    exitBtn->setFont(QFont("宋体",20));
    exitBtn->move(840,600);

    QMessageBox *messageBox = new QMessageBox(this);
    QPushButton *ok = new QPushButton("ok");
    QPushButton *cancel = new QPushButton("cancel");

    messageBox->setWindowTitle("退出游戏");
    messageBox->setText("确认退出游戏吗?");

    messageBox->addButton(ok,QMessageBox::AcceptRole);
    messageBox->addButton(cancel,QMessageBox::RejectRole);

    connect(exitBtn,&QPushButton::clicked,[=]{
        timer->stop();
        sound->stop();
        messageBox->exec();
        QSound::play(":/src source/tip_music.wav");

        if(messageBox->clickedButton() == ok){
            GameSelect *gSelect = new GameSelect;
            this->close();
            gSelect->show();
        }
        else{
            messageBox->close();
            timer->start();
            sound->play();
        }
    });
}

3.10、渲染积分、绘制结束游戏

绘制积分与绘制结束游戏这边不在过多赘述,判断结束我们运用上编写的checkFail()即可,其他代码编写即可。

    //绘制积分
    pix.load(":/src source/integral.png");
    painter.drawPixmap(800,60,50,40,pix);

    QPen pen;
    pen.setColor(Qt::black);
    painter.setPen(pen);
    QFont font("方正舒体",35);
    painter.setFont(font);
    painter.drawText(875,95,QString("%1").arg(snakeList.size()));

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

        sound = new QSound(":/src source/fail.wav");
        sound->setLoops(0);
        sound->play();
    }

3.11、写入、获取分数

当得到的分数需要进行永久的保存,要么写入硬盘中要么写在数据库中,我们暂且先写在文件中,写入文件我们使用QFile库,在利用QTextStream对文件输入输出数据,编写格式可以观看代码编写。
代码如下:

    //往文件写分数
    int c = snakeList.size();
    //初始创建文件
    QFile file("./1.txt");

    // 打开文件以写入模式,记录分数
    if(file.open(QIODevice::WriteOnly | QIODevice::Text)){
        QTextStream out (&file);
        int num = c;
        out << num;
        file.close();
    }

	//获取分数
	QFile file("./1.txt");
	file.open(QIODevice::ReadOnly);
	
	QTextStream in(&file);
	int date = in.readLine().toInt();
	edit->setText("上次分数为:");
	edit->append(QString::number(date) + QString("分"));

四、完整代码块

1、游戏主页面

1.1、gamepage.h

#ifndef GAMEPAGE_H
#define GAMEPAGE_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class GamePage; }
QT_END_NAMESPACE

class GamePage : public QWidget
{
    Q_OBJECT

public:
    GamePage(QWidget *parent = nullptr);
    ~GamePage();
    void paintEvent(QPaintEvent *event);

private:
    Ui::GamePage *ui;
};
#endif // GAMEPAGE_H

1.2、gamepage.cpp

#include "gamepage.h"
#include "ui_gamepage.h"
#include <gameselect.h>
#include <QPainter>
#include <QIcon>
#include <QPushButton>
#include <QSound>

GamePage::GamePage(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::GamePage)
{
    ui->setupUi(this);

    //设置窗口固定大小
    this->setFixedSize(1000,700);
    //设置图标
    this->setWindowIcon(QIcon(":/src source/snake.png"));
    this->setWindowTitle("贪吃蛇游戏");

    //添加按钮
    QPushButton *start = new QPushButton(this);
    //移动按钮位置
    start->setObjectName("start");
    start->move(400,500);
    start->setText("开始游戏");
    //设置字体和大小
    start->setFont(QFont("宋体",25));
    //利用QSS去修改按钮样式
    this->setStyleSheet("#start{"
                        "border: 0px;"
                        "border-radius: 30px;"
                        "background-color: #dadbde;"
                        "padding:20px;}"
                        "#start:hover{"
                        "border: 2px solid #8f8f91}"
                        "#start:pressed {"
                        "background-color: #f6f7fa;};");
    connect(start,&QPushButton::clicked,[=]{
        GameSelect *gameSelect = new GameSelect();
        gameSelect->setGeometry(this->geometry());
        this->close();
        QSound::play(":/src source/tip_music.wav");

        gameSelect->show();

    });


}

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

void GamePage::paintEvent(QPaintEvent *event)
{
    (void)event;
    QPainter painter(this);
    QPixmap pix(":/src source/interface.jpg");
    painter.drawPixmap(0,0,this->width(),this->height(),pix);
}

2、游戏难度选择

2.1、gameselect.h

#ifndef GAMESELECT_H
#define GAMESELECT_H

#include <QWidget>

namespace Ui {
class GameSelect;
}

class GameSelect : public QWidget
{
    Q_OBJECT

public:
    explicit GameSelect(QWidget *parent = nullptr);
    ~GameSelect();
    void paintEvent(QPaintEvent *event);

private:
    Ui::GameSelect *ui;

};

#endif // GAMESELECT_H

2.2、gameselect.cpp

#include "gameselect.h"
#include "ui_gameselect.h"
#include "gamepage.h"
#include "gameroom.h"
#include <QIcon>
#include <QPushButton>
#include <QSound>
#include <QPainter>
#include <QTextEdit>
#include <QFile>
#include <QTextStream>

GameSelect::GameSelect(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::GameSelect)
{
    ui->setupUi(this);

    //设置窗口固定大小
    this->setFixedSize(1000,700);
    //设置图标
    this->setWindowIcon(QIcon(":/src source/snake.png"));
    this->setWindowTitle("游戏关卡选择");

    //设置一个返回的按钮
    QPushButton *backBtn = new QPushButton(this);
    backBtn->setObjectName("backBrn");
    backBtn->setIcon(QIcon(":/src source/return.png"));
    backBtn->setStyleSheet("#backBrn{border: 1px solid #8f8f91; padding: 10px;background-color:#e1ffff;}"
                           "#backBrn:hover{border: 2px solid #ff0000;}");
    backBtn->move(this->geometry().width()-200,this->geometry().height()-180);
    connect(backBtn,&QPushButton::clicked,[=]{
       this->close();
       GamePage *gamePage = new GamePage;
       gamePage->show();
       QSound::play(":/src source/tip_music.wav");
    });

    //创建游戏房间界面
    GameRoom *gRoom = new GameRoom();


    //设置按钮的属性
    QFont font("宋体",25);
    QString style("QPushButton{"
                  "border: 0px;"
                  "border-radius: 30px;"
                  "background-color: #dadbde;"
                  "padding:20px;}"
                  "QPushButton:hover{"
                  "border: 2px solid #8f8f91}"
                  "QPushButton:pressed {"
                  "background-color: #f6f7fa;};");
    QPushButton *simpleBut = new QPushButton(this);
    simpleBut->move(390,120);
    simpleBut->setText("简单模式");
    simpleBut->setFont(font);
    simpleBut->setStyleSheet(style);
    connect(simpleBut,&QPushButton::clicked,[=]{
        this->close();
        gRoom->setGeometry(this->geometry());
        QSound::play(":/src source/tip_music.wav");
        gRoom->show();
        gRoom->setTimeout(300);
    });


    QPushButton *normalBut = new QPushButton(this);
    normalBut->move(390,240);
    normalBut->setText("普通模式");
    normalBut->setFont(font);
    normalBut->setStyleSheet(style);
    connect(normalBut,&QPushButton::clicked,[=]{
        this->close();
        gRoom->setGeometry(this->geometry());
        QSound::play(":/src source/tip_music.wav");
        gRoom->show();
        gRoom->setTimeout(200);
    });

    QPushButton *hardBut = new QPushButton(this);
    hardBut->move(390,360);
    hardBut->setText("困难模式");
    hardBut->setFont(font);
    hardBut->setStyleSheet(style);
    connect(hardBut,&QPushButton::clicked,[=]{
        this->close();
        gRoom->setGeometry(this->geometry());
        QSound::play(":/src source/tip_music.wav");
        gRoom->show();
        gRoom->setTimeout(100);
    });

    QPushButton *hisBut = new QPushButton(this);
    hisBut->move(390,480);
    hisBut->setText("历史战绩");
    hisBut->setFont(font);
    hisBut->setStyleSheet(style);

    connect(hisBut,&QPushButton::clicked,[=]{
        QWidget *widget = new QWidget();
        widget->setWindowTitle("历史战绩");
        widget->setFixedSize(400,240);

        QTextEdit *edit = new QTextEdit(widget);
        edit->setFont(font);
        edit->setFixedSize(400,240);

        QFile file("./1.txt");
        file.open(QIODevice::ReadOnly);

        QTextStream in(&file);
        int date = in.readLine().toInt();
        edit->setText("上次分数为:");
        edit->append(QString::number(date) + QString("分"));

        widget->show();
        file.close();
    });
}

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

void GameSelect::paintEvent(QPaintEvent *event)
{
    (void)event;
    QPainter painter(this);
    QPixmap pix(":/src source/game_select.png");
    painter.drawPixmap(0,0,this->width(),this->height(),pix);
}

3、游戏房间界面

3.1、gameroom.h

#ifndef GAMEROOM_H
#define GAMEROOM_H

#include <QWidget>
#include <QSound>

//表示蛇移动的方向
enum class SnakeDirect{
    UP = 0,
    DOWN,
    LEFT,
    RIGHT
};


namespace Ui {
class GameRoom;
}

class GameRoom : public QWidget
{
    Q_OBJECT

public:
    explicit GameRoom(QWidget *parent = nullptr);
    ~GameRoom();
    void paintEvent(QPaintEvent *event);

    //蛇方向移动的方法
    void moveUp();
    void moveDown();
    void moveLeft();
    void moveRight();

    //检测游戏是否结束
    bool checkFail();

    //创建食物
    void createNewFood();

    //设置蛇的移动时间
    void setTimeout(int timeout){
        moveTimeout = timeout;
    }

private:
    Ui::GameRoom *ui;

    const int kSnakeNodeWidth = 20; //表示蛇身体节点的宽度
    const int kSnakeNodeHeight = 20;//表示蛇身体节点的高度
    const int kDefaultTimeout = 200;//表示蛇默认移动速度

    QList<QRectF> snakeList;//表示贪吃蛇链表
    QRectF foodRect;//表示食物节点

    SnakeDirect moveDirect = SnakeDirect::UP;//表示蛇默认移动方向
    QTimer *timer;//定时器

    bool isGameStart = false;//表示是否开始游戏

    //游戏背景音乐
    QSound *sound;

    //设置移动速度变量
    int moveTimeout = kDefaultTimeout;
};

#endif // GAMEROOM_H

3.2、gameroom.cpp

#include "gameroom.h"
#include "ui_gameroom.h"
#include "gameselect.h"
#include <QIcon>
#include <QPainter>
#include <QDebug>
#include <QTimer>
#include <QPushButton>
#include <QMessageBox>
#include <QLabel>
#include <QFile>
#include <QDebug>

GameRoom::GameRoom(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::GameRoom)
{
    ui->setupUi(this);
    this->setFixedSize(1000,700);
    this->setWindowIcon(QIcon(":/src source/snake.png"));
    this->setWindowTitle("游戏房间");

    //初始化声音
    sound = new QSound(":/src source/bgm.wav",this);

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


    //创建食物
    createNewFood();

    //使用定时器
    timer = new QTimer(this);

    connect(timer,&QTimer::timeout,[=]{
        int cnt = 1;
        if(snakeList.front().intersects(foodRect)){//intersects方法作用是判断两个矩形框是否有相交
            createNewFood();
            cnt++;
            QSound::play(":/src source/succ.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;
            }
        }

        snakeList.pop_back();
        update();//用于刷新链表
    });

    QPushButton *start = new QPushButton("开始",this);
    QPushButton *stop = new QPushButton("停止",this);

    start->setObjectName("start");
    stop->setObjectName("stop");

    QFont font("宋体",10);
    start->setFont(font);
    stop->setFont(font);

    start->move(820,180);
    stop->move(820,240);

    connect(start,&QPushButton::clicked,[=]{
        if(!isGameStart){
            isGameStart = true;
            timer->start(moveTimeout);//设置定时器触发时间
            sound = new QSound(":/src source/bgm.wav",this);
            sound->play();
            sound->setLoops(-1);
        }
    });
    connect(stop,&QPushButton::clicked,[=]{
        if(isGameStart){
            isGameStart = false;
            timer->stop();
            sound->stop();
        }
    });

    //方向控制
    QPushButton *up = new QPushButton(QIcon(":/src source/up.png"),"上",this);
    QPushButton *down = new QPushButton(QIcon(":/src source/down.png"),"下",this);
    QPushButton *left = new QPushButton(QIcon(":/src source/left.png"),"左",this);
    QPushButton *right = new QPushButton(QIcon(":/src source/right.png"),"右",this);

    up->move(840,400);
    down->move(840,480);
    left->move(780,440);
    right->move(880,440);

    connect(up,&QPushButton::clicked,[=]{
        if(moveDirect != SnakeDirect::DOWN)
            moveDirect = SnakeDirect::UP;
    });
    connect(down,&QPushButton::clicked,[=]{
        if(moveDirect != SnakeDirect::UP    )
            moveDirect = SnakeDirect::DOWN;
    });
    connect(left,&QPushButton::clicked,[=]{
        if(moveDirect != SnakeDirect::RIGHT)
            moveDirect = SnakeDirect::LEFT;
    });
    connect(right,&QPushButton::clicked,[=]{
        if(moveDirect != SnakeDirect::LEFT)
            moveDirect = SnakeDirect::RIGHT;
    });

    up->setShortcut(QKeySequence("Up"));
    down->setShortcut(QKeySequence("Down"));
    left->setShortcut(QKeySequence("Left"));
    right->setShortcut(QKeySequence("Right"));

    start->setShortcut((QKeySequence("Space")));

    //退出游戏
    QPushButton *exitBtn = new QPushButton("退出",this);
    exitBtn->setFont(QFont("宋体",20));
    exitBtn->move(840,600);

    QMessageBox *messageBox = new QMessageBox(this);
    QPushButton *ok = new QPushButton("ok");
    QPushButton *cancel = new QPushButton("cancel");

    messageBox->setWindowTitle("退出游戏");
    messageBox->setText("确认退出游戏吗?");

    messageBox->addButton(ok,QMessageBox::AcceptRole);
    messageBox->addButton(cancel,QMessageBox::RejectRole);

    connect(exitBtn,&QPushButton::clicked,[=]{
        timer->stop();
        sound->stop();
        messageBox->show();
        messageBox->exec();
        QSound::play(":/src source/tip_music.wav");

        if(messageBox->clickedButton() == ok){
            GameSelect *gSelect = new GameSelect;
            this->close();
            gSelect->show();
        }
        else{
            messageBox->close();
            timer->start();
            sound->play();
        }
    });
}

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

void GameRoom::paintEvent(QPaintEvent *event)
{
    (void)event;

    //绘制游戏背景
    QPainter painter(this);
    QPixmap pix;
    pix.load(":/src source/game_img.jpg");
    painter.drawPixmap(0,0,750,700,pix);
    pix.load(":/src source/game_back.jpg");
    painter.drawPixmap(750,0,300,700,pix);

    //绘制蛇 蛇头 + 蛇身体 + 蛇尾巴
    //绘制蛇头:上 下 左 右
    if(moveDirect == SnakeDirect::UP){
        pix.load(":/src source/head_up.png");
    }
    else if(moveDirect == SnakeDirect::DOWN){
        pix.load(":/src source/head_down.png");
    }
    else if(moveDirect == SnakeDirect::LEFT){
        pix.load(":/src source/head_left.png");
    }
    else if(moveDirect == SnakeDirect::RIGHT){
        pix.load(":/src source/head_right.png");
    }

    auto snakeHead = snakeList.front();
    painter.drawPixmap(snakeHead.x(),snakeHead.y(),snakeHead.width(),snakeHead.height(),pix);

    //绘制蛇身
    pix.load(":/src source/body.png");
    for (int i = 1; i < snakeList.size() - 1; i++) {
        auto node = snakeList.at(i);
        painter.drawPixmap(node.x(),node.y(),node.width(),node.height(),pix);
    }

    //绘制蛇尾
    auto snakeTail = snakeList.back();
    painter.drawPixmap(snakeTail.x(),snakeTail.y(),snakeTail.width(),snakeTail.height(),pix);

    //绘制食物
    pix.load(":/src source/meal.png");
    painter.drawPixmap(foodRect.x(),foodRect.y(),foodRect.width(),foodRect.height(),pix);

    //绘制积分
    pix.load(":/src source/integral.png");
    painter.drawPixmap(800,60,50,40,pix);

    QPen pen;
    pen.setColor(Qt::black);
    painter.setPen(pen);
    QFont font("方正舒体",35);
    painter.setFont(font);
    painter.drawText(875,95,QString("%1").arg(snakeList.size()));

    //往文件写分数
    int c = snakeList.size();
    //初始创建文件
    QFile file("./1.txt");

    // 打开文件以写入模式,记录分数
    if(file.open(QIODevice::WriteOnly | QIODevice::Text)){
        QTextStream out (&file);
        int num = c;
        out << num;
        file.close();
    }



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

        sound = new QSound(":/src source/fail.wav");
        sound->setLoops(0);
        sound->play();
    }

}

void GameRoom::moveUp()
{
    QPointF leftTop;    //左上角坐标
    QPointF rightBottom;//右下角坐标

    auto snakeNode = snakeList.front();//蛇头
    int headX = snakeNode.x();
    int headY = snakeNode.y();

    if(headY < 0){
        leftTop = QPointF(headX,this->height() - kSnakeNodeHeight);
    }
    else{
        leftTop = QPointF(headX,headY - kSnakeNodeHeight);
    }

    rightBottom = leftTop + QPointF(kSnakeNodeWidth,kSnakeNodeHeight);

    snakeList.push_front(QRectF(leftTop,rightBottom));

}

void GameRoom::moveDown()
{
    QPointF leftTop;    //左上角坐标
    QPointF rightBottom;//右下角坐标

    auto snakeNode = snakeList.front();//蛇头
    int headX = snakeNode.x();
    int headY = snakeNode.y();

    if(headY > this->height()){
        leftTop = QPointF(headX,0);
    }
    else{
        leftTop = snakeNode.bottomLeft();//获取矩形左下角的坐标
    }

    rightBottom = leftTop + QPointF(kSnakeNodeWidth,kSnakeNodeHeight);

    snakeList.push_front(QRectF(leftTop,rightBottom));
}

void GameRoom::moveLeft()
{
    QPointF leftTop;    //左上角坐标
    QPointF rightBottom;//右下角坐标

    auto snakeNode = snakeList.front();//蛇头
    int headX = snakeNode.x();
    int headY = snakeNode.y();

    if(headX < 0){
        leftTop = QPointF(700 - kSnakeNodeWidth,headY);
    }
    else{
        leftTop = QPointF(headX - kSnakeNodeWidth,headY);
    }

    rightBottom = leftTop + QPointF(kSnakeNodeWidth,kSnakeNodeHeight);

    snakeList.push_front(QRectF(leftTop,rightBottom));
}

void GameRoom::moveRight()
{
    QPointF leftTop;    //左上角坐标
    QPointF rightBottom;//右下角坐标

    auto snakeNode = snakeList.front();//蛇头
    int headX = snakeNode.x();
    int headY = snakeNode.y();

    if(headX > 700){
        leftTop = QPointF(0,headY);
    }
    else{
        leftTop = snakeNode.topRight();//获取矩形右上角坐标
    }

    rightBottom = leftTop + QPointF(kSnakeNodeWidth,kSnakeNodeHeight);

    snakeList.push_front(QRectF(leftTop,rightBottom));
}

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

void GameRoom::createNewFood()
{
    foodRect = QRectF(qrand() % (750 / kSnakeNodeWidth) * kSnakeNodeWidth,
                      qrand() % (this->height() / kSnakeNodeHeight) * kSnakeNodeHeight,
                      kSnakeNodeWidth, kSnakeNodeHeight);
}


总结

  这是贪吃蛇全部啦,如想看源码可去gitee去获取喔。https://gitee.com/edwin2edd/greedy_snake_project

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智慧农业——生成式人工智能如何改变农业

在数字化转型时代&#xff0c;农业不再仅仅与土壤、水和阳光有关。随着生成式人工智能的出现&#xff0c;农业正变得更加智能、高效&#xff0c;并且越来越以数据为主导。从以前所未有的准确度预测作物产量到开发抗病植物品种&#xff0c;生成式人工智能使农民能够做出精确的决…

c语言个人笔记

linux嵌入式C语言 课程链接: [史上最强最细腻的linux嵌入式C语言学习教程李慧芹老师] 0. gcc与vim的使用 gcc 指令 -Wall:显示所有警告 gcc默认的警告包括真正的错误&#xff1a;error和 告警warning 执行过程 c源代码.c -> 预处理(E) -> 编译(S) -> 汇编©.o…

Clickhouse集群化(五)clickhouse语法学习

1. 基础 1.1. 建表建库 CREATE DATABASE IF NOT EXISTS helloworld use default; CREATE TABLE IF NOT EXISTS system_cpu_info (uuid String, -- 主机的唯一标识符source String, -- 数据来源标识resource_pool Strin…

011_IO体系

Java的IO流是实现输入/输出的基础&#xff0c;它可以方便地实现数据的输入/输出操作&#xff0c;在Java中把不同的输入/输出源抽象表述为"流"。 流是一组有顺序的&#xff0c;有起点和终点的字节集合&#xff0c;是对数据传输的总称或抽象。即数据在两设备间的传输称…

代码随想录 刷题记录-18 动态规划(1)基本理论及习题

一、基本理论 什么是动态规划 动态规划&#xff0c;英文&#xff1a;Dynamic Programming&#xff0c;简称DP&#xff0c;如果某一问题有很多重叠子问题&#xff0c;使用动态规划是最有效的。 所以动态规划中每一个状态一定是由上一个状态推导出来的&#xff0c;这一点就区分…

码云 云片滑块 分析

声明: 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 有相关问题请第一时间头像私信联系我…

小乌龟运动控制-3两只小乌龟

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目…

【自动驾驶】决策规划算法 | 数学基础(一)五次多项式详解

写在前面&#xff1a; &#x1f31f; 欢迎光临 清流君 的博客小天地&#xff0c;这里是我分享技术与心得的温馨角落。&#x1f4dd; 个人主页&#xff1a;清流君_CSDN博客&#xff0c;期待与您一同探索 移动机器人 领域的无限可能。 &#x1f50d; 本文系 清流君 原创之作&…

Mysql系列—3.体系架构

目录 Mysql体系结构 Connectors&#xff1a; 连接池和线程管理&#xff1a; SQL Interface&#xff1a; Parser&#xff08;查询解析器&#xff09;&#xff1a; Optimizer&#xff08;优化器&#xff09;&#xff1a; Caches&#xff08;缓存&#xff09;&#xff1a; …

Clickhouse集群化(四)使用clickhouse-operator部署clickhouse集群

clickhouse operator实际下就是帮助我们自动化的生产一些clickhouse配置文件信息&#xff0c;在目录/etc/clickhouse-server/的config.d conf.d users.d 1.1. 部署clickhouse operateor 下载clickhouse-operator.yaml文件 wget https://raw.githubusercontent.com/Altinity/…

Vue3 前端导出Excel表格 Xlsx格式

介绍 xlsx 是一个用于处理 Excel 文件的流行库。可以你读取、生成和操作 Excel 文件&#xff08;.xlsx 格式&#xff09;&#xff0c;提供了强大的功能来处理工作表和单元格数据。可以轻松地将 JSON 数据转换为 Excel 表格&#xff0c;也可以从 Excel 文件中读取数据。 安装 …

【Linux篇】网络请求和下载与端口

目录 1. 网络请求和下载 1.1 ping命令 1.2 wget命令 1.3 curl命令 2. 端口 2.1 查看端口占用 使用nmap命令&#xff0c;安装nmap&#xff1a;yum -y install nmap 可以通过netstat命令&#xff0c;查看指定端口的占用情况。 3. 进程管理 3.1 进程 3.2 查看进程 3.3 …

Llama 4B剪枝蒸馏实战

大型语言模型 (LLM) 因其有效性和多功能性&#xff0c;如今已成为自然语言处理和理解领域的主导力量。LLM&#xff08;例如 Llama 3.1 405B 和 NVIDIA Nemotron-4 340B&#xff09;在许多具有挑战性的任务中表现出色&#xff0c;包括编码、推理和数学。然而&#xff0c;它们的部…

异步编程之std::future(二): std::future和std::promise原理

目录 1.引言 2.源码分析 2.1.std::promise的源码实现 2.2.std::future的源码实现 2.3.关联状态对象的代码实现 3.整个类图 4.future和promise之间的并发安全和线程同步 5.总结 1.引言 异步编程之std::future(一): 使用-CSDN博客 在std::future(一)中详…

【bug】可图文生图模型 KolorsPipeline IndexError: list index out of range

【bug】可图文生图模型 KolorsPipeline IndexError: list index out of range 环境 linux diffusers 0.30.0问题详情 报错详情 from diffusers import KolorsPipelineTraceback (most recent call last):File "Kolors/demo.py", line 6, in <module>pi…

Vue(2)——Vue指令

目录 v-html v-show和v-if v-else和v-else-if v-on v-bind v-for v-model v-html 设置元素的innerHTML <body><div id"app"><div v-html"msg"></div></div><script src"https://cdn.jsdelivr.net/npm/vue2.…

大模型从入门到精通——基于智谱AI和LangChain实现RAG应用(一)

基于智谱AI和LangChain实现RAG应用(一) 1. 使用 LangChain 调用智谱 GLM 1.1 自定义chatglm #!/usr/bin/env python # -*- encoding: utf-8 -*-from typing import Any, List, Mapping, Optional, Dict from langchain_core.callbacks.manager import CallbackManagerForLLM…

统一身份认证服务(CAS)系统实现SSO认识

一、前言 CAS&#xff08;Central Authentication Service&#xff09;即中央认证服务&#xff0c;是 Yale 大学发起的一个企业级开源项目&#xff0c;旨在为 Web 应用系统提供一种可靠的 SSO 解决方案&#xff0c;它是一个企业级的开源单点认证登录解决方案&#xff0c;采用ja…

netty编程之UDP

写在前面 源码 。 UDP&#xff0c;user datagram protocol,是internet协议簇中无连接的传输协议&#xff0c;因为无连接所以相比于TCP需要维护更少的信息以及网络交互&#xff0c;所以具有更高的效率。本文看下netty是如何实现的&#xff0c;和TCP方式差别不大&#xff0c;下面…

【宝马中国-注册/登录安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…