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

原文地址:https://www.cnblogs.com/lizijuna/p/11907438.html