zoukankan      html  css  js  c++  java
  • QT写的贪吃蛇(C++)

    这个qt写的贪吃蛇是我在通过学校老师所录的视频简单学习之后,再根据网络上的视频(视频是在腾讯课堂上找的,我现在也找不到原视频了)做出的一个贪吃蛇小游戏。该游戏所实现的功能如下:

    1. 资源文件的使用
    2. 父子窗口的协调出现,父窗口的背景覆盖
    3. 蛇头和食物初次出现的随机数
    4. 按键函数的使用
    5. 绘图事件的使用
    6. 按钮组的使用
    7. 同一个按钮点击连接不同槽

    最终游戏界面如下:游戏进入界面

    游戏进入界面
    游戏主要界面
    游戏主界面
    ⒈下面是相关文件的说明:
    snake.pro为配置文件,widget为父窗口相关文件,gamewidget为子窗口相关文件
    snake.pro为配置文件
    widget为父窗口相关文件
    gamewidget为子窗口相关文件
    main.cpp没有做更改,默认数据
    ⒉widget.h中的代码

    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include<QWidget>
    #include<QIcon>
    #include<QPalette>
    #include<QBrush>
    #include<QPixmap>
    #include<QPushButton>
    #include<QMessageBox>
    
    #include"gamewidget.h"
    
    
    class Widget : public QWidget
    {
        Q_OBJECT
    
    public:
        Widget(QWidget *parent = 0);
        ~Widget();
        QPushButton *startPush;
        QPushButton *exitPush;
        QMessageBox *exitBox;
        Gamewidget  *gamewindow;//声明一个新的界面
    
    private slots:
        void M_startPush();
        void M_exitPush();
    
    };
    
    #endif // WIDGET_H
    

    ⒊widget.cpp中的代码

     #include "widget.h"
    #include"gamewidget.h"
    #include<QDebug>
    
    
    Widget::Widget(QWidget *parent)
        : QWidget(parent)
    {
        this->resize(891,510);
        this->setWindowTitle("李子的贪吃蛇");
        this->setWindowIcon(QIcon(":/Picture/img/WindowPicture.jpg"));
        QPalette palette;
        palette.setBrush(QPalette::Background,QBrush(QPixmap(":/Picture/img/Back2.jpg")));
        this->setStyleSheet("background-image:url(qrc:/new/Gamewindow/img/GameBack.jpg)");
        this->setPalette(palette);
    
        startPush=new QPushButton(this);
        exitPush=new QPushButton(this);
        startPush->setIconSize(QSize(920,45));
        startPush->setGeometry(400,360,90,45);
        startPush->setIcon(QIcon(":/Picture/img/Start.png"));
        startPush->setFlat(1);
        exitPush->setIconSize(QSize(90,45));
        exitPush->setGeometry(400,420,90,45);
        exitPush->setIcon(QIcon(":/Picture/img/Exit.png"));
        exitPush->setFlat(1);//设置按钮的透明属性
    
        exitBox=new QMessageBox;
        connect(exitPush,SIGNAL(clicked(bool)),this,SLOT(M_exitPush()));
        connect(startPush,SIGNAL(clicked(bool)),this,SLOT(M_startPush()));
    }
    
    void Widget::M_startPush()
    {
        gamewindow=new Gamewidget(this);  //创建一个新的界面,任然以原来的界面为父窗口,退出后可以直接回到上一个界面。
        gamewindow->show();
    }
    void Widget::M_exitPush()
    {
        if(QMessageBox::Yes==QMessageBox::question(this,"Tips:","Do you want to leave th ox:⒋gamewidget.h中的代码:No))
        {
          
      delet  this;
            exit(0);
        }
    }
    
    

    ⒋gamewidget.h中的代码

    #ifndef GAMEWIDGET_H
    #define GAMEWIDGET_H
    
    #include <QWidget>
    #include<QIcon>
    #include<QPalette>
    #include<QBrush>
    #include<QPixmap>
    #include<QPushButton>
    #include<QMessageBox>
    #include<QPaintEvent>
    #include<QPainter>
    #include<QLabel>
    #include<QTimer>
    #include<QTime>
    #include<ctime>
    #include<QButtonGroup>
    #include<QKeyEvent>
    #define longnumber 20//宏定义游戏界面方格的多少
    #define widthnumber 16
    
    class Gamewidget : public QWidget
    {
        Q_OBJECT
    public:
        explicit Gamewidget(QWidget *parent = 0);
        void paintEvent(QPaintEvent*);
        void keyPressEvent(QKeyEvent *e);
        QPushButton *upPush;
        QPushButton *downPush;
        QPushButton *leftPush;
        QPushButton *rightPush;
        QPushButton *StartPush;
        QPushButton *ExitPush;
        QLabel *ScoreLabel;
        QLabel *LevelLabel;
        QLabel *ScoreLabelNumber;
        QLabel *LevelLabelNumber;
        QTimer *Timer;
        int snake[200][2];//创建了一个包含蛇的身体坐标的数组
        int snake1[200][2];//这个数组只是上一个坐标的复制,在最后一步(咬到身体或者撞到边缘)需要将它的身体坐标还原
        static  int m_setDiretion;//对方向的更改的存储
        QButtonGroup *buttonGroup;//上下左右四个键构成一个按钮组,根据它们的返回值改变方向的值
        int foodx;//食物的X坐标
        int foody;//食物的Y坐标
        int bodycount;
        bool Nobite;
        int Score;
        int Difficulty;//难度级别,时间变化
    private:
        QPalette *palette;
    
    signals:
    
    public slots:
        void M_timeout();
        void M_startPush();
        void M_setDiretion(int index);
        void M_exitPush();
        void M_pausePush();
        void M_CheckGameOver();
    };
    
    #endif // GAMEWIDGET_H
    
    

    ⒌gamewidget.cpp中的代码

    #include "gamewidget.h"
    #include"widget.h"
    #include<QDebug>
    
    int Gamewidget::m_setDiretion=4;
    Gamewidget::Gamewidget(QWidget *parent) : QWidget(parent)
    {
        qsrand(time(NULL));//随机数的种子
        Score=0;
        Difficulty=1;
        this->setAutoFillBackground(true);//设置父窗口背景可被覆盖填充
        this->resize(891,510);
        this->setWindowTitle("李子的贪吃蛇");
        this->setWindowIcon(QIcon(":/Picture/img/WindowPicture.jpg"));
    
        QPalette palette;
        palette.setBrush(QPalette::Background,QBrush(QPixmap(":/new/Gamewindow/img/GameBack.jpg").scaled(this->size())));
        this->setPalette(palette);
    
    
        upPush =new QPushButton(this);
        downPush=new QPushButton(this);
        leftPush=new QPushButton(this);
        rightPush=new QPushButton(this);
        StartPush=new QPushButton(this);
        ExitPush=new QPushButton(this);
    
        buttonGroup=new QButtonGroup(this);
        buttonGroup->addButton(upPush,1);
        buttonGroup->addButton(downPush,2);
        buttonGroup->addButton(leftPush,3);
        buttonGroup->addButton(rightPush,4);
        connect(buttonGroup,SIGNAL(buttonClicked(int)),this,SLOT(M_setDiretion(int)));
    
    
        upPush->setIconSize(QSize(45,90));
        upPush->setGeometry(750,160,45,90);
        upPush->setIcon(QIcon(":/new/Gamewindow/img/up.png"));
        upPush->setFlat(1);
        downPush->setIconSize(QSize(45,90));
        downPush->setGeometry(750,260,45,90);
        downPush->setIcon(QIcon(":/new/Gamewindow/img/down.png"));
        downPush->setFlat(1);
        leftPush->setIconSize(QSize(90,45));
        leftPush->setGeometry(650,230,90,45);
        leftPush->setIcon(QIcon(":/new/Gamewindow/img/left.png"));
        leftPush->setFlat(1);
        rightPush->setIconSize(QSize(90,45));
        rightPush->setGeometry(800,230,90,45);
        rightPush->setIcon(QIcon(":/new/Gamewindow/img/right.png"));
        rightPush->setFlat(1);
    
        StartPush->setIconSize(QSize(90,45));
        StartPush->setGeometry(650,400,90,45);
        StartPush->setFlat(1);
        StartPush->setIcon(QIcon(":/Picture/img/Start.png"));
    
    
        ExitPush->setIconSize(QSize(90,45));
        ExitPush->setGeometry(780,400,90,45);
        ExitPush->setIcon(QIcon(":/Picture/img/Exit.png"));
        ExitPush->setFlat(1);
    
        ScoreLabel=new QLabel(this);
        LevelLabel=new QLabel(this);
        ScoreLabel->setText("Score:");
        ScoreLabel->setGeometry(690,10,120,90);
        LevelLabel->setText("Level:");
        LevelLabel->setGeometry(690,50,120,90);
    
        ScoreLabelNumber=new QLabel(this);
        LevelLabelNumber=new QLabel(this);
        ScoreLabelNumber->setText(QString::number(Score)+"分");
        ScoreLabelNumber->setGeometry(750,10,120,90);
        LevelLabelNumber->setText(QString::number(Difficulty)+"级");
        LevelLabelNumber->setGeometry(750,50,120,90);
    
        Timer=new QTimer(this);
        connect(Timer,SIGNAL(timeout()),this,SLOT(M_timeout()));
        connect(StartPush,SIGNAL(clicked(bool)),this,SLOT(M_startPush()));
        connect(ExitPush,SIGNAL(clicked(bool)),this,SLOT(M_exitPush()));
    
        snake[0][0]=(rand()%18+1)*30+30;
        snake[0][1]=(rand()%15+1)*30+30;
        m_setDiretion=(rand()%4)+1;
        foodx=(rand()%20)*30;
        foody=(rand()%15)*30;
        bodycount=1;  //包含蛇的头和尾巴
        Nobite=true;
        this->repaint();
    
    }
    void Gamewidget::keyPressEvent(QKeyEvent *e)//按键处理
    {
        switch(e->key())
        {
        case Qt::Key_Up:if(m_setDiretion!=2)m_setDiretion=1;  break;
        case Qt::Key_W:if(m_setDiretion!=2)m_setDiretion=1;  break;
        case Qt::Key_Down:if(m_setDiretion!=1)m_setDiretion=2;  break;
        case Qt::Key_S:if(m_setDiretion!=1)m_setDiretion=2;  break;
        case Qt::Key_Left:if(m_setDiretion!=4)m_setDiretion=3;  break;
        case Qt::Key_A:if(m_setDiretion!=4)m_setDiretion=3;  break;
        case Qt::Key_Right:if(m_setDiretion!=3)m_setDiretion=4;  break;
        case Qt::Key_D:if(m_setDiretion!=3)m_setDiretion=4;  break;
        default:                   break;
    
        }
    }
    void Gamewidget::paintEvent(QPaintEvent*)//绘图事件
    {
        QPainter painter(this);
        if(0<=snake[0][0]&&snake[0][0]<=600&&0<=snake[0][1]&&snake[0][1]<=480&&Nobite)
        {
            qDebug()<<snake[0][0];
            for(int i=bodycount;i>0;i--)
            {
                if(i==bodycount)//画出尾巴部分
                {
                    if(snake[i][0]==snake[i-1][0]&&snake[i][1]<snake[i-1][1])
                    {
                        painter.drawImage(QRect(snake[i][0],snake[i][1],30,30),QImage(":/new/Gamewindow/img/taildown.png"));
                    }
                    else  if(snake[i][0]==snake[i-1][0]&&snake[i][1]>snake[i-1][1])
                    {
                        painter.drawImage(QRect(snake[i][0],snake[i][1],30,30),QImage(":/new/Gamewindow/img/tailup.png"));
                    }
                    else  if(snake[i][0]<snake[i-1][0]&&snake[i][1]==snake[i-1][1])
                    {
                        painter.drawImage(QRect(snake[i][0],snake[i][1],30,30),QImage(":/new/Gamewindow/img/tailright.png"));
                    }
                    else  if(snake[i][0]>snake[i-1][0]&&snake[i][1]==snake[i-1][1])
                    {
                        painter.drawImage(QRect(snake[i][0],snake[i][1],30,30),QImage(":/new/Gamewindow/img/tailleft.png"));
                    }
                }
                else
                {
                    if((snake[i][0]==snake[i-1][0]&& snake[i][1]<snake[i-1][1]&&snake[i+1][0]<snake[i][0]&&snake[i+1][1]==snake[i][1])||
                            ((snake[i][0]>snake[i-1][0])&& snake[i][1]==snake[i-1][1]&&snake[i+1][0]==snake[i][0]&&snake[i+1][1]>snake[i][1]))
                    {
                        painter.drawImage(QRect(snake[i][0],snake[i][1],30,30),QImage(":/new/Gamewindow/img/leftdown.png"));
                    }
                    else if((snake[i][0]<snake[i-1][0]&& snake[i][1]==snake[i-1][1]&&snake[i+1][0]==snake[i][0]&&snake[i+1][1]>snake[i][1])||
                            (snake[i][0]==snake[i-1][0]&& snake[i][1]<snake[i-1][1]&&snake[i+1][0]>snake[i][0]&&snake[i+1][1]==snake[i][1]))
                    {
                        painter.drawImage(QRect(snake[i][0],snake[i][1],30,30),QImage(":/new/Gamewindow/img/rightdown.png"));
                    }
                    else if((snake[i][0]>snake[i-1][0]&& snake[i][1]==snake[i-1][1]&&snake[i+1][0]==snake[i][0]&&snake[i+1][1]<snake[i][1])||
                            (snake[i][0]==snake[i-1][0]&& snake[i][1]>snake[i-1][1]&&snake[i+1][0]<snake[i][0]&&snake[i+1][1]==snake[i][1]))
                    {
                        painter.drawImage(QRect(snake[i][0],snake[i][1],30,30),QImage(":/new/Gamewindow/img/leftup.png"));
                    }
                    else if(((snake[i][0]==snake[i-1][0])&& snake[i][1]>snake[i-1][1]&&snake[i+1][0]>snake[i][0]&&snake[i+1][1]==snake[i][1])||
                            (snake[i][0]<snake[i-1][0]&& snake[i][1]==snake[i-1][1]&&snake[i+1][0]==snake[i][0]&&snake[i+1][1]<snake[i][1]))
                    {
                        painter.drawImage(QRect(snake[i][0],snake[i][1],30,30),QImage(":/new/Gamewindow/img/rightup.png"));
                    }
    
                    else if((snake[i][0]==snake[i-1][0]&&snake[i][0]==snake[i+1][0])&&((snake[i][1]<snake[i-1][1]&&snake[i+1][1]<snake[i][1])||
                                                                                       (snake[i][1]>snake[i-1][1]&&snake[i+1][1]>snake[i][1])))
                    {
                        painter.drawImage(QRect(snake[i][0],snake[i][1],30,30),QImage(":/new/Gamewindow/img/downup.png"));
    
                    }
                    else if ((snake[i][1]==snake[i-1][1]&&snake[i][1]==snake[i+1][1])&&((snake[i][0]<snake[i-1][0]&&snake[i+1][0]<snake[i][0])||
                                                                                        (snake[i][0]>snake[i-1][0]&&snake[i+1][0]>snake[i][0])))
                    {
                        painter.drawImage(QRect(snake[i][0],snake[i][1],30,30),QImage(":/new/Gamewindow/img/leftright.png"));
    
                    }
                }
            }
        }
        painter.drawImage(QRect(foodx,foody,30,30),QImage(":/new/Gamewindow/img/Apple.png"));
    
        painter.setPen(Qt::green);
    
        for(int i=0;i<=widthnumber;i++)
        {
            for(int j=0;j<=longnumber;j++)
            {
                painter.drawRect(QRect(30*j,30*i,30,30));
            }
        }
        switch (m_setDiretion)
        {
        case 1: painter.drawImage(QRect(snake[0][0],snake[0][1],30,30),QImage(":/new/Gamewindow/img/headup.png"));
            if(bodycount==1)  painter.drawImage(QRect(snake[0][0],snake[0][1]+30,30,30),QImage(":/new/Gamewindow/img/tailup.png"));
            break;
        case 2: painter.drawImage(QRect(snake[0][0],snake[0][1],30,30),QImage(":/new/Gamewindow/img/headdown.png"));
            if(bodycount==1) painter.drawImage(QRect(snake[0][0],snake[0][1]-30,30,30),QImage(":/new/Gamewindow/img/taildown.png"));
            break;
        case 3: painter.drawImage(QRect(snake[0][0],snake[0][1],30,30),QImage(":/new/Gamewindow/img/headleft.png"));
            if(bodycount==1) painter.drawImage(QRect(snake[0][0]+30,snake[0][1],30,30),QImage(":/new/Gamewindow/img/tailleft.png"));
            break;
        case 4: painter.drawImage(QRect(snake[0][0],snake[0][1],30,30),QImage(":/new/Gamewindow/img/headright.png"));
            if(bodycount==1)  painter.drawImage(QRect(snake[0][0]-30,snake[0][1],30,30),QImage(":/new/Gamewindow/img/tailright.png"));
            break;
        default:
            break;
        }
    }
    
    void Gamewidget::M_timeout()
    {
        if(snake[0][0]==foodx&&snake[0][1]==foody)//当蛇头的坐标与食物坐标重合的时候,重新布置食物的位置
        {
            foodx=(rand()%20)*30;
            foody=(rand()%15)*30;
            bodycount++;  //蛇的身体加一
            Difficulty=bodycount/5+1;
            Score=Score+Difficulty;
            ScoreLabelNumber->setText(QString::number(Score)+"分");
            LevelLabelNumber->setText(QString::number(Difficulty)+"级");
            Timer->start(800-Difficulty>0? 800-Difficulty*80:80/(Difficulty-8));
        }
        memcpy(snake1,snake,sizeof(snake));
        for(int i=bodycount;i>0;i--)//将蛇身体的前一个坐标赋值给后一个坐标,实现蛇身体的连续出现
        {
    
            snake[i][0]=snake[i-1][0];
            snake[i][1]=snake[i-1][1];
        }
        QPainter painter(this);
    
        for(int i=bodycount;i>3;i--)
        {
            if(snake[0][0]==snake[i][0]&&snake[0][1]==snake[i][1])
            {
                Nobite=false;
            }
        }
    
        switch (m_setDiretion)
        {
        case 1: snake[0][1]=snake[0][1]-30,painter.drawImage(QRect(snake[0][0],snake[0][1],30,30),QImage(":/new/Gamewindow/img/headup.png"))
                    ;break;
        case 2: snake[0][1]=snake[0][1]+30,painter.drawImage(QRect(snake[0][0],snake[0][1],30,30),QImage(":/new/Gamewindow/img/headdown.png"))
                    ; break;
        case 3: snake[0][0]=snake[0][0]-30,painter.drawImage(QRect(snake[0][0],snake[0][1],30,30),QImage(":/new/Gamewindow/img/headleft.png"))
                    ; break;
        case 4: snake[0][0]=snake[0][0]+30,painter.drawImage(QRect(snake[0][0],snake[0][1],30,30),QImage(":/new/Gamewindow/img/headright.png"))
                    ;break;
        default:
            break;
        }
        if(0>snake[0][0]||snake[0][0]>600||0>snake[0][1]||snake[0][1]>480)
        {
            memcpy(snake,snake1,sizeof(snake));
            Nobite=false;
        }
    
        this->update();
        connect(Timer,SIGNAL(timeout()),this,SLOT(M_CheckGameOver()));
    }
    
    void Gamewidget::M_startPush()//时间函数开始计时
    {
        Timer->start(800);
        disconnect(StartPush,SIGNAL(clicked(bool)),this,SLOT(M_startPush()));
        StartPush->setIcon(QIcon(":/Picture/img/Pause.png"));
        connect(StartPush,SIGNAL(clicked(bool)),this,SLOT(M_pausePush()));
    }
    void Gamewidget::M_pausePush()//实现开始与暂停按钮的管理
    {
        Timer->stop();
        connect(StartPush,SIGNAL(clicked(bool)),this,SLOT(M_startPush()));
        StartPush->setIcon(QIcon(":/Picture/img/Start.png"));
        disconnect(StartPush,SIGNAL(clicked(bool)),this,SLOT(M_pausePush()));
    }
    
    void Gamewidget::M_setDiretion(int index)//接收按钮组的整数,确定方向
    {
        switch (index)
        {
        case 1:if(m_setDiretion!=2)m_setDiretion=1;  break;
        case 2:if(m_setDiretion!=1)m_setDiretion=2;  break;
        case 3:if(m_setDiretion!=4)m_setDiretion=3;  break;
        case 4:if(m_setDiretion!=3)m_setDiretion=4;  break;
        default:                   break;
        }
    }
    
    void Gamewidget::M_exitPush()
    {
        this->close();
        delete this;
    }
    
    
    void Gamewidget::M_CheckGameOver()//该部分原本在绘图事件函数中,但是由于在其中的时候程序总是意外关闭,故将其提出
    {
    
    
        if(0>snake[0][0]||snake[0][0]>600||0>snake[0][1]||snake[0][1]>480||(!Nobite))
        {
            Nobite=true;//将其设置为真,进入绘图函数画出蛇的身体
            this->update();//调用绘图事件函数
            Timer->stop();
            if(QMessageBox::Yes==QMessageBox::information(this,"Tips:","Game Over!",QMessageBox::Yes))
            {
                this ->hide();
                delete this;
                return;
            }
    
        }
    
    }
    
    

    PS:这个游戏存在两个BUG
    ①由于游戏最开始设置绘图刷新在500ms,在这个时间内,连续按键可能导致蛇头出现反向,进而导致Game Over。
    ②游戏界面的图片不能随窗口大小而变化,放大窗口会出现重复图片
    以上就是所有的源代码,这里附上代码的文件,包括图片资源文件,百度云网址:贪吃蛇(百度云界面若是显示文件不存在按F5刷新一下就好) 由于我是qt的初学者,这些代码有些部分难免会显得特别冗长,也希望各位能够指出,以供我学习一下。

  • 相关阅读:
    将vue文件script代码抽取到单独的js文件
    git pull 提示错误:Your local changes to the following files would be overwritten by merge
    vue和uniapp 配置项目基础路径
    XAMPP Access forbidden! Access to the requested directory is only available from the local network.
    postman与newman集成
    postman生成代码段
    Curl命令
    POST方法的Content-type类型
    Selenium Grid 并行的Web测试
    pytorch转ONNX以及TnesorRT的坑
  • 原文地址:https://www.cnblogs.com/lizijuna/p/11907438.html
Copyright © 2011-2022 走看看