Qt写基础贪吃蛇小项目

一.项目演示

Greed

二.使用Qt_Creator创建项目名

1.选择Application,创建Qt Widgets Application

然后一直下一步创建完毕

2.渲染游戏大厅界面,如图所示

下方为gamehall.h 期中的paintEvent为虚函数可以进行重写,用于绘制界面

#ifndef GAMEHALL_H
#define GAMEHALL_H

#include <QWidget>
#include<QPainter>
QT_BEGIN_NAMESPACE
namespace Ui { class GameHall; }
QT_END_NAMESPACE
class GameHall : public QWidget
{
    Q_OBJECT
public:
    GameHall(QWidget *parent = nullptr);
    ~GameHall();
    //重写绘图事件
    void paintEvent(QPaintEvent *event);
private:
    Ui::GameHall *ui;
};
#endif // GAMEHALL_H

 绘制界面时可以创建qrc资源文件如下步骤

将准备好的资源复制粘贴到项目文件中就可以进行使用 更方便一些了

gamehall.cpp中  为窗口设置大小,设置标题,以及图标创建画家实例化,实例绘图,画家记性绘制页面

 

GameHall::GameHall(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::GameHall)
{
    ui->setupUi(this);
    //设置窗口大小
    this->setFixedSize(1000,800);
    //设置窗口标题
    this->setWindowTitle("贪吃蛇");
    //设置窗口图标
    this->setWindowIcon(QIcon(":/ico.png"));

    //设置字体 大小
    QFont font("微软雅黑",24);

}
void GameHall::paintEvent(QPaintEvent *event)
{
    //实例化画家
    QPainter painter(this);
    //QPixmap  实例化绘图设备
    QPixmap pix(":/game_hall.png");
    //绘画
    painter.drawPixmap(0,0,this->width(),this->height(),pix);
}

此时运行一下页面为 

因为我们是设置点击有声音效果的打开API 后QSound需要 添加multimedia

3.先添加qmke声音配置

配置完成以后就可以使用QSound 声音效果了

4.添加开始按钮

效果如下

代码如下

//开始游戏按钮
    QPushButton*strBtn=new QPushButton(this);
    strBtn->setFont(font);
    strBtn->setText("开始游戏");//设置开始文字
    strBtn->move(430,530);
    //取消开始游戏的边框
    strBtn->setStyleSheet("QPushButton{border:0px;}");

    QPushButton*exitButton=new QPushButton(this);
    exitButton->setText("退出游戏");
    exitButton->move(430,650);
    exitButton->setFont(font);
    // 去除边框
    exitButton->setStyleSheet("QPushButton{border:0px;}");

5.给开始按钮,退出按钮设置信号槽 

开始按钮时我们要跳转到另一个页面,需要新建c++ class类

开始 退出按钮代码如下

 GameSelect*gameSelect=new GameSelect;
    connect(strBtn,&QPushButton::clicked,[=](){
        this->close();
        //设置第二个窗口和第一个大小一样
        gameSelect->setGeometry(this->geometry());
        gameSelect->show();
        QSound::play(":clicked.wav");
    });
    //退出游戏
    connect(exitButton,&QPushButton::clicked,[=](){
        this->close();
    });

点击开始按钮就会跳转到新的页面,点击退出游戏时就关闭游戏 ,下图是点击开始游戏初始页面

三.绘制游戏开始选项页面

1.gameselect.h页面代码

#ifndef GAMESELECT_H
#define GAMESELECT_H

#include <QWidget>
#include<QPainter>
class GameSelect : public QWidget
{
    Q_OBJECT
public:
    explicit GameSelect(QWidget *parent = nullptr);

    void paintEvent(QPaintEvent *event);
signals:

};

#endif // GAMESELECT_H

同gamehall.h  我们绘制页面需要用到paintEvent 

2.gamehall.cpp 中 painEvent代码

void GameSelect::paintEvent(QPaintEvent *event)
{
    //实例化画家
    QPainter painter(this);
    //QPixmaap  实例化绘图设备
    QPixmap pix(":/game_select.png");
    painter.drawPixmap(0,0,this->width(),this->height(),pix);
}

3.设置页面的标题,大小,图标,以及添加各类按钮

//创建返回按钮
    QPushButton*backButton=new QPushButton(this);
    //设置返回按钮图标
    backButton->setIcon(QIcon(":/back.png"));
    //设置返回按钮位置
    backButton->move(900,720);

    QFont font("微软雅黑",23);
    
    QPushButton*simpleButton=new QPushButton(this);
    simpleButton->setText("简单模式");
    simpleButton->setFont(font);
    simpleButton->move(400,150);


    QPushButton*normalButton=new QPushButton(this);
    normalButton->setText("正常模式");
    normalButton->setFont(font);
    normalButton->move(400,300);

    QPushButton*hardButton=new QPushButton(this);
    hardButton->setText("困难模式");
    hardButton->setFont(font);
    hardButton->move(400,500);

    QPushButton*historyButton=new QPushButton(this);
    historyButton->setText("历史战绩");
    historyButton->setFont(font);
    historyButton->move(400,700);

4.目前运行程序如图所示

5.给右下角返回按钮添加信号槽机制,点击就返回第一个页面

    connect(backButton,&QPushButton::clicked,[=](){

        this->close();

        QSound::play(":/clicked.wav");
        GameHall*gamehall=new GameHall();
        gamehall->show();

    });

 6.创建第三个页面游戏房间页面,当点击模式后进入房间

四.绘制游戏房间

1.gameroom.h代码如下

#ifndef GAMEROOM_H
#define GAMEROOM_H
#include<QPainter>
#include <QObject>
#include <QWidget>
#include<QTimer>
#include<QList>
#include<QSound>
enum class SnakeDirect{//枚举设置蛇的方向
    UP=0,
    DOWN,
    LEFT,
    RIGHT
};

class GameRoom : public QWidget
{
    Q_OBJECT
public:
    explicit GameRoom(QWidget *parent = nullptr);
    void paintEvent(QPaintEvent *event);//重新绘画事件
    void moveup();//向上移动
    void moveDown();//蛇向下移动
    void moveLeft();//向左移动
    void moveRight();//向右移动
    bool checkFail();//判断游戏是否结束
    void createNewFood();//食物创建
    void setTimeOut(int timeout){
        moveTimeOut=timeout;
    }
signals:
private:
    const int KSnakeNodeWidth=20;//表示蛇身体节点的宽度
    const int kSnakeNodeHeight=20;//表示蛇身体节点的高度
    const int KDefaultTimeout=200;//蛇默认移动速度
    QList<QRectF>snakeList;
    QRectF foodRect;//表示食物节点
    SnakeDirect moveDirect=SnakeDirect::UP;//设置蛇的默认方向上
    QTimer*timer;//定时器
    QSound *sound;
    bool isGameStart=false;//表示是否可以开始游戏
    int moveTimeOut=KDefaultTimeout;

};
#endif // GAMEROOM_H

1.首先设置大小,窗口标题,设置划分区域,渲染游戏页面

void GameRoom::paintEvent(QPaintEvent *event)
{
    //实例化画家
    QPainter painter(this);
    
    //QPixmap
    QPixmap pix;
    
    pix.load(":/heiwukong.png");
    painter.drawPixmap(0,0,800,800,pix);
    
    pix.load(":/bg1.png");
    painter.drawPixmap(800,0,200,900,pix);}
GameRoom::GameRoom(QWidget *parent) : QWidget(parent)
{
    this->setWindowTitle("游戏页面");//设置标题
    this->setWindowIcon(QIcon(":/ico.png"));//设置图标
    this->setFixedSize(1000,800);}

 2.向上移动的实现

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));//节点更新到链表中
  
    //snakeList.push_back(QRectF(leftTop,rightBottom));
}

3.向下移动的实现

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

 4.向左移动的实现

void GameRoom::moveLeft()
{
    QPointF leftTop;
    QPointF rightBottom;
    
    auto snakeNode=snakeList.front();
    
    int headX=snakeNode.x();
    int headY=snakeNode.y();
    
    if(headX<0)
    {
        leftTop=QPointF(800-KSnakeNodeWidth,headY);
    }else
    {
        leftTop=QPointF(headX-KSnakeNodeWidth,headY);
    }
    rightBottom=leftTop+QPointF(KSnakeNodeWidth,kSnakeNodeHeight);
    snakeList.push_front(QRectF(leftTop,rightBottom));
}

 5.向右移动的实现

void GameRoom::moveRight()
{
    QPointF leftTop;//左上角坐标
    QPointF rightBottom;//右下角坐标
    auto snakeNode=snakeList.front();
    int headX=snakeNode.x();
    int headY=snakeNode.y();
    if(headX+KSnakeNodeWidth>780)
    {
        
        leftTop=QPointF(0,headY);
    }else
    {
       
        leftTop=snakeNode.topRight();
    }
    
    rightBottom=leftTop+QPointF(KSnakeNodeWidth,kSnakeNodeHeight);
    snakeList.push_front(QRectF(leftTop,rightBottom));
}

6.判断游戏是否结束

当蛇身之间互相碰撞时,即蛇身上的节点重合时游戏结束

bool GameRoom::checkFail()
{
    for(int i=0;i<snakeList.size();i++)
    {
        for(int j=i+1;j<snakeList.size();j++)
        {
            //获取两个节点的位置 如果相同为true结束游戏
            if(snakeList.at(i)==snakeList.at(j))
            {
                return true;
            }
        }
    }
    return false;
}

 7.渲染贪吃蛇

 //加载蛇头的资源文件

    if(moveDirect==SnakeDirect::UP)
    {
        pix.load(":/up.png");
    }else if(moveDirect==SnakeDirect::DOWN)
    {
        pix.load(":/down.png");
    }else if(moveDirect==SnakeDirect::LEFT)
    {
        pix.load(":/left.png");
    }else if(moveDirect==SnakeDirect::RIGHT)
    {
        pix.load(":/right.png");
    }
    auto snakeHead=snakeList.front();//获取蛇头节点
    painter.drawPixmap(snakeHead.x(),snakeHead.y(),snakeHead.width(),snakeHead.height(),pix);

    //绘制蛇身
    pix.load(":/Bd.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 snakeTaile=snakeList.back();
    painter.drawPixmap(snakeTaile.x(),snakeTaile.y(),snakeTaile.width(),snakeTaile.height(),pix);

8.初始化贪吃蛇

在GameRoom::GameRoom(QWidget *parent) : QWidget(parent)中

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

 9.渲染食物

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

10.当吃上食物时增添一个节点并删除最后节点

 //创建食物
    createNewFood();
    
    timer=new QTimer(this);
    connect(timer,&QTimer::timeout,[=](){
        
        int cnt=1;
        if(snakeList.front().intersects(foodRect))//判断两个矩形 食物和蛇头会不会相交
        {
            createNewFood();
            cnt++;//统计相交的次数
            QSound::play(":/eatfood.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();//更新链表
    });

 11.设置开始 和 停止按钮

QPushButton*startButton=new QPushButton(this);
    QPushButton*stopButton=new QPushButton(this);
    startButton->move(860,150);
    startButton->setText("开始");
    stopButton->move(860,240);
    stopButton->setText("停止");
    //startButton->setStyleSheet("QPushButton{border:0px}");
    //stopButton->setStyleSheet("QPushButton{border:0px}");
    QFont font("微软雅黑",20);
    startButton->setFont(font);
    stopButton->setFont(font);
    sound=new QSound(":/taicongming.wav");
    connect(startButton,&QPushButton::clicked,[=](){
        isGameStart=true;
        timer->start(moveTimeOut);
        sound->play();
        sound->setLoops(-1);//为真一直播放
    });
    
    //停止
    connect(stopButton,&QPushButton::clicked,[=](){
        isGameStart=false;
        timer->stop();
        sound->stop();
    });

 12.设置四个方向按钮控制蛇的移动

 //方向控制
    QPushButton*up=new QPushButton(this);
    QPushButton*down=new QPushButton(this);
    QPushButton*left=new QPushButton(this);
    QPushButton*right=new QPushButton(this);
    
    up->move(880,400);
    down->move(880,500);
    left->move(840,450);
    right->move(920,450);
    
    up->setText("↑");
    down->setText("↓");
    left->setText("←");
    right->setText("→");
    
    up->setStyleSheet("QPushButton{border:0px}");
    down->setStyleSheet("QPushButton{border:0px}");
    left->setStyleSheet("QPushButton{border:0px}");
    right->setStyleSheet("QPushButton{border:0px}");
    
    QFont ft("黑体",35);
    up->setFont(ft);
    down->setFont(ft);
    left->setFont(ft);
    right->setFont(ft);
    //规定上箭头
    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;
        }
    });

13.设置退出游戏按钮,弹出消息框

 

//设置退出按钮
    QPushButton*exitButton=new QPushButton(this);
    exitButton->setText("退出游戏");
    exitButton->setFont(font);
    
    exitButton->move(830,700);
    //设置消息弹出框
    QMessageBox*messageBox=new QMessageBox(this);
    
    QPushButton*ok=new QPushButton("ok");
    QPushButton*cancel=new QPushButton("cancel");
    
    //按钮添加到消息盒子
    messageBox->addButton(ok,QMessageBox::AcceptRole);
    messageBox->addButton(cancel,QMessageBox::RejectRole);
    messageBox->setWindowTitle("退出游戏");
    messageBox->setText("确认退出游戏吗?????");
    connect(exitButton,&QPushButton::clicked,[=](){
        isGameStart=false;
        timer->stop();
        sound->stop();
        
        messageBox->show();
        messageBox->exec();//事件轮询
        QSound::play(":/clicked.wav");
        
        GameSelect*select=new GameSelect;
        if(messageBox->clickedButton()==ok)
        {
            this->close();
            
            select->show();
        }else
        {
            messageBox->close();
        }
    });

如图所示

 14.渲染积分以及失败效果

 //绘制分数
    pix.load(":/sorce_bg.png");
    painter.drawPixmap(this->width()*0.85,this->height()*0.06,90,40,pix);
    //画笔
    QPen pen;
    pen.setColor(Qt::black);
    painter.setPen(pen);
    QFont font("方正舒体",22);
    painter.setFont(font);
    painter.drawText(this->width()*0.9,this->height()*0.1,QString("%1").arg(snakeList.size()));
    //往文件里面写入分数
    int score=snakeList.size();
    QFile file("D:/SSNNake/1.txt");
    if(file.open(QIODevice::WriteOnly|QIODevice::Text))//判断是否打开了
    {
        QTextStream out(&file);
        int num=score;
        out<<num;
        file.close();
    }
    //渲染绘制失败效果
    if(checkFail())
    {
        pen.setColor(Qt::red);
        painter.setPen(pen);
        QFont font1("方正舒体",50);
        painter.setFont(font1);
        painter.drawText(this->width()*0.25,this->height()*0.5,
                         QString("GAME OVEER!"));
        timer->stop();
        sound->stop();
        int count=1;
        while(count--)
        {
            QSound::play(":/nizaibuzai.wav");
        }
    }

 15.设置三种不同的模式难度

回到gameselect.cpp中 

 connect(simpleButton,&QPushButton::clicked,[this](){
        this->close();
        GameRoom *gameroom=new GameRoom;
        gameroom->show();
        gameroom->setGeometry(this->geometry());
        QSound::play(":/clicked.wav");
        gameroom->setTimeOut(350);
    });


    connect(normalButton,&QPushButton::clicked,[=](){
        this->close();
        GameRoom *gameroom=new GameRoom;
        gameroom->show();
        gameroom->setGeometry(this->geometry());
        QSound::play(":/clicked.wav");
        gameroom->setTimeOut(300);
    });
    connect(hardButton,&QPushButton::clicked,[=](){
        this->close();
        GameRoom *gameroom=new GameRoom;
        gameroom->show();
        gameroom->setGeometry(this->geometry());
        QSound::play(":/clicked.wav");
        gameroom->setTimeOut(200);
    });

16.网文件写入历史战绩,并打开文件获取历史战绩

connect(historyButton,&QPushButton::clicked,[=](){
        QWidget*widget=new QWidget();
        widget->setWindowTitle("历史战绩");
        //设置窗口大小
        widget->setFixedSize(500,300);
        QTextEdit*edit=new QTextEdit(widget);
        edit->setFont(font);
        edit->setFixedSize(500,300);
        QFile file("D:/SSNNake/1.txt");
        file.open(QIODevice::ReadOnly);
        QTextStream in(&file);
        //读取历史战绩 将读出的字符串转化成int
        // int data=in.readLine().toInt();
        //追加历史战绩 将 int类型转化成 字符串String
        // edit->append(QString::number(data));
        edit->append("得分为:");
        edit->append(in.readLine());
        widget->show();
    });

写入历史战绩

 //往文件里面写入分数
    int score=snakeList.size();
    QFile file("D:/SSNNake/1.txt");
    if(file.open(QIODevice::WriteOnly|QIODevice::Text))//判断是否打开了
    {
        QTextStream out(&file);
        int num=score;
        out<<num;
        file.close();
    }

 五.全部代码

gamehall.h

#ifndef GAMEHALL_H
#define GAMEHALL_H

#include <QWidget>
#include<QPainter>
QT_BEGIN_NAMESPACE
namespace Ui { class GameHall; }
QT_END_NAMESPACE
class GameHall : public QWidget
{
    Q_OBJECT
public:
    GameHall(QWidget *parent = nullptr);
    ~GameHall();
    //重写绘图事件
    void paintEvent(QPaintEvent *event);
private:
    Ui::GameHall *ui;
};
#endif // GAMEHALL_H

gamehall.cpp

#include "gamehall.h"
#include "ui_gamehall.h"
#include<QPixmap>
#include<QPainter>
#include<QIcon>
#include<gameselect.h>
#include<QPushButton>
#include<QLabel>
#include<QFont>
#include<QSound>
GameHall::GameHall(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::GameHall)
{
    ui->setupUi(this);
    //设置窗口大小
    this->setFixedSize(1000,800);
    //设置窗口标题
    this->setWindowTitle("贪吃蛇");
    //设置窗口图标
    this->setWindowIcon(QIcon(":/ico.png"));

    //设置字体 大小
    QFont font("微软雅黑",24);
    //开始游戏按钮
    QPushButton*strBtn=new QPushButton(this);


    strBtn->setFont(font);
    strBtn->setText("开始游戏");//设置开始文字

    strBtn->move(430,530);
    //取消开始游戏的边框
    strBtn->setStyleSheet("QPushButton{border:0px;}");

    //跳转到第二个窗口
    GameSelect*gameSelect=new GameSelect;
    connect(strBtn,&QPushButton::clicked,[=](){
        this->close();
        //设置第二个窗口和第一个大小一样
      //  gameSelect->setGeometry(this->geometry());
        gameSelect->show();

        QSound::play(":clicked.wav");


    });

    //退出游戏
    QPushButton*exitButton=new QPushButton(this);

    exitButton->setText("退出游戏");

    exitButton->move(430,650);
    exitButton->setFont(font);

    // 去除边框
    exitButton->setStyleSheet("QPushButton{border:0px;}");
    connect(exitButton,&QPushButton::clicked,[=](){
        //关闭是没有声音的
       //QSound::play(":clicked.wav");
      this->close();

    });
}

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

void GameHall::paintEvent(QPaintEvent *event)
{
    //实例化画家
    QPainter painter(this);
    //QPixmap  实例化绘图设备
    QPixmap pix(":/game_hall.png");
    //绘画
    painter.drawPixmap(0,0,this->width(),this->height(),pix);
}


 gameselect.h

#ifndef GAMESELECT_H
#define GAMESELECT_H

#include <QWidget>
#include<QPainter>
class GameSelect : public QWidget
{
    Q_OBJECT
public:
    explicit GameSelect(QWidget *parent = nullptr);

    void paintEvent(QPaintEvent *event);
signals:

};

#endif // GAMESELECT_H

gameselect .cpp

#include "gameselect.h"
#include"gamehall.h"
#include<QIcon>
#include<QPushButton>
#include<QSound>
#include<QPixmap>
#include<QFont>
#include"gameroom.h"
#include<QTextEdit>
#include<QFile>
#include<QTextStream>
GameSelect::GameSelect(QWidget *parent) : QWidget(parent)
{

    //设置窗口大小
    this->setFixedSize(1000,800);
    //设置窗口标题
    this->setWindowTitle("游戏选择关卡");
    //设置窗口图标
    this->setWindowIcon(QIcon(":/ico.png"));

    //创建返回按钮
    QPushButton*backButton=new QPushButton(this);
    //设置返回按钮图标
    backButton->setIcon(QIcon(":/back.png"));
    //设置返回按钮位置
    backButton->move(900,720);

    connect(backButton,&QPushButton::clicked,[=](){

        this->close();

        QSound::play(":/clicked.wav");
        GameHall*gamehall=new GameHall();
        gamehall->show();

    });
    QFont font("微软雅黑",23);


    QPushButton*simpleButton=new QPushButton(this);
    simpleButton->setText("简单模式");
    simpleButton->setFont(font);
    simpleButton->move(400,150);


    QPushButton*normalButton=new QPushButton(this);
    normalButton->setText("正常模式");
    normalButton->setFont(font);
    normalButton->move(400,300);

    QPushButton*hardButton=new QPushButton(this);
    hardButton->setText("困难模式");
    hardButton->setFont(font);
    hardButton->move(400,500);

    connect(simpleButton,&QPushButton::clicked,[this](){
        this->close();
        GameRoom *gameroom=new GameRoom;
        gameroom->show();
        gameroom->setGeometry(this->geometry());
        QSound::play(":/clicked.wav");
        gameroom->setTimeOut(350);
    });


    connect(normalButton,&QPushButton::clicked,[=](){
        this->close();
        GameRoom *gameroom=new GameRoom;
        gameroom->show();
        gameroom->setGeometry(this->geometry());
        QSound::play(":/clicked.wav");
        gameroom->setTimeOut(300);
    });
    connect(hardButton,&QPushButton::clicked,[=](){
        this->close();
        GameRoom *gameroom=new GameRoom;
        gameroom->show();
        gameroom->setGeometry(this->geometry());
        QSound::play(":/clicked.wav");
        gameroom->setTimeOut(200);
    });

    QPushButton*historyButton=new QPushButton(this);
    historyButton->setText("历史战绩");
    historyButton->setFont(font);
    historyButton->move(400,700);

    connect(historyButton,&QPushButton::clicked,[=](){
        QWidget*widget=new QWidget();
        widget->setWindowTitle("历史战绩");
        //设置窗口大小
        widget->setFixedSize(500,300);

        QTextEdit*edit=new QTextEdit(widget);
        edit->setFont(font);
        edit->setFixedSize(500,300);
        QFile file("D:/SSNNake/1.txt");
        file.open(QIODevice::ReadOnly);

        QTextStream in(&file);
        //读取历史战绩 将读出的字符串转化成int
        // int data=in.readLine().toInt();
        //追加历史战绩 将 int类型转化成 字符串String
        // edit->append(QString::number(data));
        edit->append("得分为:");
        edit->append(in.readLine());
        widget->show();
    });
}


void GameSelect::paintEvent(QPaintEvent *event)
{
    //实例化画家
    QPainter painter(this);
    //QPixmaap  实例化绘图设备
    //QPixmap pix(":/game_select.png");
   QPixmap pix(":/danzai.png");
    painter.drawPixmap(0,0,this->width(),this->height(),pix);
}

gameroom.h

#ifndef GAMEROOM_H
#define GAMEROOM_H
#include<QPainter>
#include <QObject>
#include <QWidget>
#include<QTimer>
#include<QList>
#include<QSound>
enum class SnakeDirect{//枚举设置蛇的方向
    UP=0,
    DOWN,
    LEFT,
    RIGHT
};

class GameRoom : public QWidget
{
    Q_OBJECT
public:
    explicit GameRoom(QWidget *parent = nullptr);

    void paintEvent(QPaintEvent *event);//重新绘画事件
    void moveup();//向上移动
    void moveDown();//蛇向下移动
    void moveLeft();//向左移动
    void moveRight();//向右移动

    bool checkFail();//判断游戏是否结束
    void createNewFood();//食物创建
    void setTimeOut(int timeout){
        moveTimeOut=timeout;
    }
signals:

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

    QList<QRectF>snakeList;

    QRectF foodRect;//表示食物节点
    SnakeDirect moveDirect=SnakeDirect::UP;//设置蛇的默认方向上
    QTimer*timer;//定时器
    QSound *sound;
    bool isGameStart=false;//表示是否可以开始游戏
    int moveTimeOut=KDefaultTimeout;

};

#endif // GAMEROOM_H

 gameroom.cpp

#include "gameroom.h"
#include<QIcon>
#include<QPixmap>
#include<QTimer>
#include<QPushButton>
#include<QFont>
#include<QSound>
#include<QMessageBox>
#include<QFile>
#include<QTextStream>
#include"gameselect.h"
GameRoom::GameRoom(QWidget *parent) : QWidget(parent)
{
    this->setWindowTitle("游戏页面");//设置标题
    this->setWindowIcon(QIcon(":/ico.png"));//设置图标
    this->setFixedSize(1000,800);
    //初始化贪吃蛇
    snakeList.push_back(QRectF(this->width()*0.5,(this->height()/2),KSnakeNodeWidth,kSnakeNodeHeight));
    moveup();
    moveup();

    //创建食物
    createNewFood();

    timer=new QTimer(this);
    connect(timer,&QTimer::timeout,[=](){

        int cnt=1;
        if(snakeList.front().intersects(foodRect))//判断两个矩形 食物和蛇头会不会相交
        {
            createNewFood();
            cnt++;//统计相交的次数
            QSound::play(":/eatfood.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*startButton=new QPushButton(this);
    QPushButton*stopButton=new QPushButton(this);
    startButton->move(860,150);
    startButton->setText("开始");

    stopButton->move(860,240);
    stopButton->setText("停止");
    //startButton->setStyleSheet("QPushButton{border:0px}");
    //stopButton->setStyleSheet("QPushButton{border:0px}");
    QFont font("微软雅黑",20);
    startButton->setFont(font);
    stopButton->setFont(font);
    sound=new QSound(":/taicongming.wav");
    connect(startButton,&QPushButton::clicked,[=](){
        isGameStart=true;
        timer->start(moveTimeOut);

        sound->play();
        sound->setLoops(-1);//为真一直播放
    });

    //停止
    connect(stopButton,&QPushButton::clicked,[=](){
        isGameStart=false;
        timer->stop();
        sound->stop();
    });
    //方向控制
    QPushButton*up=new QPushButton(this);
    QPushButton*down=new QPushButton(this);
    QPushButton*left=new QPushButton(this);
    QPushButton*right=new QPushButton(this);

    up->move(880,400);
    down->move(880,500);
    left->move(840,450);
    right->move(920,450);

    up->setText("↑");
    down->setText("↓");
    left->setText("←");
    right->setText("→");

    up->setStyleSheet("QPushButton{border:0px}");
    down->setStyleSheet("QPushButton{border:0px}");
    left->setStyleSheet("QPushButton{border:0px}");
    right->setStyleSheet("QPushButton{border:0px}");

    QFont ft("黑体",35);
    up->setFont(ft);
    down->setFont(ft);
    left->setFont(ft);
    right->setFont(ft);
    //规定上箭头
    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;
        }
    });

    //设置退出按钮
    QPushButton*exitButton=new QPushButton(this);
    exitButton->setText("退出游戏");
    exitButton->setFont(font);

    exitButton->move(830,700);
    //设置消息弹出框
    QMessageBox*messageBox=new QMessageBox(this);

    QPushButton*ok=new QPushButton("ok");
    QPushButton*cancel=new QPushButton("cancel");

    //按钮添加到消息盒子
    messageBox->addButton(ok,QMessageBox::AcceptRole);
    messageBox->addButton(cancel,QMessageBox::RejectRole);
    messageBox->setWindowTitle("退出游戏");
    messageBox->setText("确认退出游戏吗?????");
    connect(exitButton,&QPushButton::clicked,[=](){
        isGameStart=false;
        timer->stop();
        sound->stop();

        messageBox->show();
        messageBox->exec();//事件轮询
        QSound::play(":/clicked.wav");

        GameSelect*select=new GameSelect;
        if(messageBox->clickedButton()==ok)
        {
            this->close();

            select->show();
        }else
        {
            messageBox->close();
        }
    });



}

void GameRoom::paintEvent(QPaintEvent *event)
{
    //实例化画家
    QPainter painter(this);

    //QPixmap
    QPixmap pix;

    pix.load(":/heiwukong.png");
    painter.drawPixmap(0,0,800,800,pix);

    pix.load(":/bg1.png");
    painter.drawPixmap(800,0,200,900,pix);
    //加载蛇头的资源文件

    if(moveDirect==SnakeDirect::UP)
    {
        pix.load(":/up.png");
    }else if(moveDirect==SnakeDirect::DOWN)
    {
        pix.load(":/down.png");
    }else if(moveDirect==SnakeDirect::LEFT)
    {
        pix.load(":/left.png");
    }else if(moveDirect==SnakeDirect::RIGHT)
    {
        pix.load(":/right.png");
    }
    auto snakeHead=snakeList.front();//获取蛇头节点
    painter.drawPixmap(snakeHead.x(),snakeHead.y(),snakeHead.width(),snakeHead.height(),pix);


    //绘制蛇身
    pix.load(":/Bd.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 snakeTaile=snakeList.back();
    painter.drawPixmap(snakeTaile.x(),snakeTaile.y(),snakeTaile.width(),snakeTaile.height(),pix);


    //绘制食物
    pix.load(":/food.bmp");
    painter.drawPixmap(foodRect.x(),foodRect.y(),foodRect.width(),foodRect.height(),pix);

    //绘制分数
    pix.load(":/sorce_bg.png");
    painter.drawPixmap(this->width()*0.85,this->height()*0.06,90,40,pix);


    //画笔
    QPen pen;
    pen.setColor(Qt::black);
    painter.setPen(pen);
    QFont font("方正舒体",22);
    painter.setFont(font);
    painter.drawText(this->width()*0.9,this->height()*0.1,QString("%1").arg(snakeList.size()));

    //往文件里面写入分数
    int score=snakeList.size();
    QFile file("D:/SSNNake/1.txt");
    if(file.open(QIODevice::WriteOnly|QIODevice::Text))//判断是否打开了
    {
        QTextStream out(&file);
        int num=score;
        out<<num;
        file.close();
    }

    //渲染绘制失败效果
    if(checkFail())
    {
        pen.setColor(Qt::red);
        painter.setPen(pen);
        QFont font1("方正舒体",50);
        painter.setFont(font1);
        painter.drawText(this->width()*0.25,this->height()*0.5,
                         QString("GAME OVEER!"));
        timer->stop();
        sound->stop();
        int count=1;
        while(count--)
        {
            QSound::play(":/nizaibuzai.wav");
        }


    }

}

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));//节点更新到链表中

    //snakeList.push_back(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(800-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+KSnakeNodeWidth>780)
    {
        //我理解的
        //leftTop=QPointF(KSnakeNodeWidth,headY);
        //他写的
        leftTop=QPointF(0,headY);
    }else
    {
        //我理解的
        //leftTop=QPointF(KSnakeNodeWidth+headX,headY);

        //他写的
        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++)
        {
            //获取两个节点的位置 如果相同为true结束游戏
            if(snakeList.at(i)==snakeList.at(j))
            {
                return true;
            }
        }
    }
    return false;
}

void GameRoom::createNewFood()
{
    //看不懂生成的随机数 不知道你想做什么
     foodRect=QRectF(qrand()%(800/KSnakeNodeWidth)*KSnakeNodeWidth,
                     qrand()%(this->height()/kSnakeNodeHeight)*kSnakeNodeHeight,
                     KSnakeNodeWidth,
                     kSnakeNodeHeight);

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值