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的初学者,这些代码有些部分难免会显得特别冗长,也希望各位能够指出,以供我学习一下。

  • 相关阅读:
    什么是“泛在电力物联网”?要建一个什么样的泛在电力物联网?
    基于混合云雾计算的物联网架构
    探索 | “中医+AI”会诊电力设备故障
    泛在电力物联网有项核心技术 你听过没有?
    国网做泛在电力物联网的初衷是什么?如何参与?
    泛在电力物联网技术及战略解读:一个战略 两个领域 三个阶段
    构建“泛在电力物联网”成为国网当前最紧迫、最重要的任务
    如何解决分布式日志exceptionless的写入瓶颈
    SQL 查找是否"存在",别再 count 了,很耗费时间的
    abp vnext 微服务-基于Exceptionless实现分布式日志记录
  • 原文地址:https://www.cnblogs.com/lizijuna/p/11907438.html
Copyright © 2011-2022 走看看