Qt实现贪吃蛇

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

界面如下

首先我们要准备相应的图组

放入Resources里面

我们对首页widget进行设置

首先我们要考虑头文件的添加

1.界面的大小与图片的大小的设置一致

setPalette()函数设置背景

QImage、QPixmap等绘图设备类都提供scaled()函数

函数原型:

QImage QImage::scaled ( int width, int height, 
Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio, 
Qt::TransformationMode transformMode = Qt::FastTransformation ) const
This is an overloaded function.
Returns a copy of the image scaled to a rectangle with the given width and height according to the given aspectRatioMode and transformMode.
If either the width or the height is zero or negative, this function returns a null image.
翻译: 
这是一个重载函数,按照指定的宽和高,根据纵横比模式和转换模式从原有图像返回一个经过比例转换的图像,如果宽高为0,返回一个空图像

所以,获取控件的改变后的宽高,就能设定图像转换的宽高转换比例,用scaled()的返回重新进行绘图即可自适应窗口

在widget.h中所需的头文件

#include<QWidget> //默认头文件
#include<QIcon>//QIcon 类代表图标
#include<QPalette>//QPalette是Qt中的一个调色板类,用于美化界面。
#include<QBrush>//绘制的形状的填充模式
#include<QPixmap>// 绘图设备
#include<QPushButton>//按钮
#include<QMessageBox>//消息对话框

#include"gamewidget.h" //子文件

QWidget类是所有用户界面对象的基类。通俗的来讲,Qt基本上所有的UI类都是由QWidget继承出来的,而QWidget继承于QObject,  大家可以查阅Qt source 即可发现一些微妙的写法。

QPixmap类是一种 off-screen 图像表示形式,可以用作绘画设备。使用QLabelQAbstractButton的子类之一(例如QPushButtonQToolButton),可以轻松地在屏幕上显示QPixmapQLabel具有pixmap属性,而QAbstractButton具有icon属性。

由于QPixmap类使用隐式数据共享,因此可以按值传递QPixmap对象。有关更多信息,请参见隐式数据共享(Implicit Data Sharing)文档。QPixmap对象也可以流式传输。

请注意,pixmap 中的像素数据是内部的,并由基础窗口系统管理。由于QPixmapQPaintDevice子类,因此QPainter可用于直接绘制到 pixmap 上。只能通过QPainter函数或将QPixmap转换为QImage来访问像素。但是,fill()函数可用于以给定的颜色初始化整个像素图。

有一些函数可以在QImageQPixmap之间进行转换。通常,在将QImage对象转换为要在屏幕上显示的QPixmap之前,使用QImage类加载图像文件,并选择处理图像数据。或者,如果不需要任何操作,则可以将图像文件直接加载到QPixmap中。

QPixmap提供了一组函数,这些函数可用于获取有关像素图的各种信息。另外,有几个函数可以转换像素图。

QPixmap类来源:https://www.jianshu.com/p/5d3022759b07

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();私有退出退出按钮函数申明

};

weiget.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;//申明调色板QPalette的使用
    palette.setBrush(QPalette::Background,QBrush(QPixmap(":/Picture/img/Back2.jpg")));//设置QPalette palette背景图片填充
    this->setStyleSheet("background-image:url(qrc:/new/Gamewindow/img/GameBack.jpg)");//设置父窗口的背景图片
    this->setPalette(palette);//
exitBox=new QMessageBox;//
    connect(exitPush,SIGNAL(clicked(bool)),this,SLOT(M_exitPush()));//信号与槽退出函数的设置
    connect(startPush,SIGNAL(clicked(bool)),this,SLOT(M_startPush()));//信号与槽开始函数的设置
Widget::~Widget()
{

}

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 the game?",QMessageBox::Yes|QMessageBox::No))
    {
        delete 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>
#include<QStyle>
#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;
        }

    }

}







mian.cpp

#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();


    return a.exec();
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值