Qt:26.Qt项目:贪吃蛇游戏

时间:2024-07-20 17:42:32

1.打开窗口实现:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPushButton>
#include <QLabel>
#include <QFont>
#include <QSound>
#include "gameselect.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    //初始化窗口,标题,图标,窗口大小
    ui->setupUi(this);
    this->setWindowTitle("贪吃蛇");
    this->setWindowIcon(QIcon(":/image/pix.png"));
    this->setFixedSize(600,400);

    //窗口背景设置,将图片设置自动拉伸
    QLabel* label=new QLabel(this);
    label->setGeometry(0,0,this->width(),this->height());
    label->setPixmap(QPixmap(":/image/enter.jpg"));
    label->setScaledContents(true);

    //设置进入按钮
    QPushButton* enter_but=new QPushButton(this);
    enter_but->move(250,250);
    enter_but->setText("进入游戏");
    enter_but->setStyleSheet("QPushButton{border:0px;color:red;}");

    //按钮文本设置
    QFont font("华文行楷",18);
    enter_but->setFont(font);

    //创建选项页面,设置点击音效,打开新窗口,关闭旧窗口
    GameSelect* gameSelect=new GameSelect;
    connect(enter_but,&QPushButton::clicked,[=]()
    {
        gameSelect->setGeometry(this->geometry());
        QSound::play(":/image/6.wav");
        gameSelect->show();
        this->close();

    });

}

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

2.选项窗口实现:

#include "gameselect.h"
#include <QIcon>
#include <QLabel>
#include <QDebug>
#include <QVBoxLayout>
#include <QPushButton>
#include <QFont>
#include "mainwindow.h"
#include <QSound>
#include "gameroom.h"
#include <QFile>

GameSelect::GameSelect(QWidget *parent) : QWidget(parent)
{

    //窗口大小固定,设置图标,标题
    this->setFixedSize(600,400);
    this->setWindowTitle("关卡选择");
    this->setWindowIcon(QIcon(":/image/pix.png"));

    //加载背景
    QLabel* label=new QLabel(this);
    label->setGeometry(this->geometry());
    label->setPixmap(QPixmap(":/image/load.jpg"));

    //创建一个widget对象存放布局管理器,管理选项按钮
    QWidget* widget=new QWidget(this);
    widget->setGeometry(150,100,300,250);

    //创建布局管理器,并将它设置到widget对象
    QVBoxLayout* layout=new QVBoxLayout;
    widget->setLayout(layout);

    //选项按钮创建
    QPushButton* but_easy=new QPushButton("简单模式");
    QPushButton* but_normal=new QPushButton("正常模式");
    QPushButton* but_diff=new QPushButton("困难模式");
    QPushButton* but_grades=new QPushButton("战绩查询");
    QPushButton* but_ret=new QPushButton("返回上页");

    //按钮添加到布局管理器
    layout->addWidget(but_easy);
    layout->addWidget(but_normal);
    layout->addWidget(but_diff);
    layout->addWidget(but_grades);
    layout->addWidget(but_ret);

    //设置按钮的拉伸策略,是的可以占满整个布局管理器
    but_easy->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    but_normal->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    but_diff->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    but_grades->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    but_ret->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);

    QFont font("华文行楷",25);
    widget->setFont(font);

    //设置按钮无边框,文本显示颜色为蓝色
    but_easy->setStyleSheet("QPushButton{border: 0px;color:blue;}");
    but_normal->setStyleSheet("QPushButton{border: 0px;color:blue;}");
    but_diff->setStyleSheet("QPushButton{border: 0px;color:blue;}");
    but_grades->setStyleSheet("QPushButton{border: 0px;color:blue;}");
    but_ret->setStyleSheet("QPushButton{border: 0px;color:blue;}");


    //连接按钮和槽函数,直接使用lambda表达式
    connect(but_ret,&QPushButton::clicked,[=]()
    {
       MainWindow* mainwindow=new MainWindow;
       QSound::play(":/image/6.wav");
       mainwindow->show();
       this->close();
    });

    GameRoom* room=new GameRoom;
    connect(but_easy,&QPushButton::clicked,[=]()
    {

        room->setGeometry(this->geometry());
        QSound::play(":/image/6.wav");
        room->show();
        this->close();

        room->setMoveTimeout(300);

    });

    connect(but_normal,&QPushButton::clicked,[=]()
    {
        room->setGeometry(this->geometry());
        QSound::play(":/image/6.wav");
        room->show();
        this->close();
        room->setMoveTimeout(200);

    });

    connect(but_diff,&QPushButton::clicked,[=]()
    {
        room->setGeometry(this->geometry());
        QSound::play(":/image/6.wav");
        room->show();
        this->close();
        room->setMoveTimeout(100);
    });

    connect(but_grades, &QPushButton::clicked, [=]() {
        QSound::play(":/image/6.wav");
        QWidget* widget = new QWidget;
        widget->setWindowTitle("历史分数");
        widget->setWindowIcon(QIcon(":/image/pix.png"));
        widget->setFixedSize(400, 200);
        QLabel* label=new QLabel(widget);
        label->setGeometry(0,0,400,200);

        QFile file("C:/Users/86133/Desktop/Qt-tmp.txt");
        file.open(QIODevice::ReadOnly);
        QTextStream in(&file);
        QString grade=in.readLine();

        QFont font("行书",30);
        label->setFont(font);

        label->setText("最近得分:"+ grade);
        widget->show();
    });

}

3.游戏窗口实现

#include "gameroom.h"
#include <QIcon>
#include <QPainter>
#include <QTimer>
#include <QPushButton>
#include <QMessageBox>
#include "gameselect.h"
#include <QFile>
#include <QTextStream>
#include <QShortcut>

GameRoom::GameRoom(QWidget *parent) : QWidget(parent)
{
    
    //初始化窗口,标题,图标,大小
    this->setWindowTitle("游戏房间");
    this->setWindowIcon(QIcon(":/image/pix.png"));
    this->setFixedSize(600,400);

    //尾插一个节点作为头节点
    snakeList.push_back(QRectF(160,220,kSnakeNodeWidth,kSnakeNodeHeight));
    moveUp();
    moveUp();

    //创建食物
    createFood();

    //定时器设置
    timer=new QTimer(this);
    connect(timer,&QTimer::timeout,[=]()
    {
        //如果吃到食物,重新生成食物
        int cnt=1;
        if(snakeList.front().intersects(foodRect))
        {
            createFood();
            cnt++;
        }

        //通过食物数量,控制移动的距离
        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* sta_but=new QPushButton("开始游戏",this);
    QPushButton* stop_but=new QPushButton("暂停游戏",this);

    sta_but->move(450,100);
    stop_but->move(450,150);

    QFont font("楷体",15);
    sta_but->setFont(font);
    stop_but->setFont(font);

    //开始功能实现,音乐播放,音乐持续播放设置
    connect(sta_but,&QPushButton::clicked,[=]()
    {
        isGameStart=true;
        timer->start(moveTimeout);
        sound=new QSound(":/image/2.wav");
        sound->play();
        sound->setLoops(-1);
    });

    connect(stop_but,&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(480,230);
    down->move(480,270);
    left->move(440,250);
    right->move(520,250);

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

    QFont ft("楷体",25);
    up->setFont(ft);
    down->setFont(ft);
    left->setFont(ft);
    right->setFont(ft);

    QShortcut* s1=new QShortcut(QKeySequence("W"),up);
    QShortcut* s2=new QShortcut(QKeySequence("S"),down);
    QShortcut* s3=new QShortcut(QKeySequence("A"),left);
    QShortcut* s4=new QShortcut(QKeySequence("D"),right);

    QObject::connect(s1,&QShortcut::activated,up,&QPushButton::click);
    QObject::connect(s2,&QShortcut::activated,down,&QPushButton::click);
    QObject::connect(s3,&QShortcut::activated,left,&QPushButton::click);
    QObject::connect(s4,&QShortcut::activated,right,&QPushButton::click);

    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* exit_but=new QPushButton("退出游戏",this);
    exit_but->move(450,350);
    exit_but->setFont(font);

    QMessageBox* msg=new QMessageBox(this);
    QPushButton* ok=new QPushButton("ok");
    QPushButton* cancel=new QPushButton("cancel");
    msg->addButton(ok,QMessageBox::AcceptRole);
    msg->addButton(cancel,QMessageBox::RejectRole);
    msg->setWindowTitle("退出");
    msg->setText("是否确定退出?");

    connect(exit_but,&QPushButton::clicked,[=]()
    {
        msg->exec();
        QSound::play(":/image/6.wav");
        if(msg->clickedButton()==ok)
        {
            GameSelect* gameselect=new GameSelect;
            gameselect->show();
            this->close();
        }
        else
        {
            msg->close();
        }
    });


}

void GameRoom::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    QPixmap pix;
    pix.load(":/image/main.jpg");
    painter.drawPixmap(0,0,400,400,pix);
    pix.load(":/image/control.jpg");
    painter.drawPixmap(400,0,200,400,pix);

    //绘制蛇头
    if(moveDirect==SnakeDirect::UP)
        pix.load(":/image/up.png");
    else if(moveDirect==SnakeDirect::DOWN)
        pix.load(":/image/down.png");
    else if(moveDirect==SnakeDirect::LEFT)
        pix.load(":/image/left.png");
    else
        pix.load(":/image/right.png");
    auto snakeHead=snakeList.front();
    painter.drawPixmap(snakeHead.x(),snakeHead.y(),snakeHead.width(),snakeHead.height(),pix);

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

    //绘制食物
    pix.load(":/image/Hamburg.png");
    painter.drawPixmap(foodRect.x(),foodRect.y(),kSnakeNodeWidth,kSnakeNodeHeight,pix);

    //将分数绘制到界面
    QPen pen;
    pen.setColor(Qt::black);
    painter.setPen(pen);
    QFont font("楷体",15);
    painter.setFont(font);

    painter.drawText(430,30,"当前等分:");
    painter.drawText(530,30,QString("%1").arg(snakeList.size()-3));

    //绘制失败效果
    if(checkFail())
    {
        pen.setColor(Qt::red);
        QFont font("楷体",30);
        painter.setPen(pen);
        painter.setFont(font);
        painter.drawText(100,180,"Game Over");
        timer->stop();
        sound->stop();
    }

    //将当前分数保存到文件中
    int c=snakeList.size()-3;
    QFile file("C:/Users/86133/Desktop/Qt-tmp.txt");
    if(file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        QTextStream out(&file);
        int num=c;
        out<<num;
        file.close();
    }


}

void GameRoom::moveUp()
{
    QPointF leftTop;
    QPointF rightBottom;
    auto snakeHead=snakeList.front();
    int headX=snakeHead.x();
    int headY=snakeHead.y();

    if(headY<20)
    {
        leftTop=QPointF(headX,this->height()-kSnakeNodeHeight);
    }
    else
    {
        leftTop=QPointF(headX,headY-kSnakeNodeHeight);
    }
    rightBottom=leftTop+QPointF(kSnakeNodeWidth,kSnakeNodeHeight);
    snakeList.push_front(QRectF(leftTop,rightBottom));
}

void GameRoom::moveDown()
{
    QPointF leftTop;
    QPointF rightBottom;
    auto snakeHead=snakeList.front();
    int headX=snakeHead.x();
    int headY=snakeHead.y();

    if(headY>this->height()-40)
    {
        leftTop=QPointF(headX,0);
    }
    else
    {
        leftTop=snakeHead.bottomLeft();
    }
    rightBottom=leftTop+QPointF(kSnakeNodeWidth,kSnakeNodeHeight);
    snakeList.push_front(QRectF(leftTop,rightBottom));
}

void GameRoom::moveLeft()
{
    QPointF leftTop;
    QPointF rightBottom;
    auto snakeHead=snakeList.front();
    int headX=snakeHead.x();
    int headY=snakeHead.y();

    if(headX<20)
    {
        leftTop=QPointF(400-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 snakeHead=snakeList.front();
    int headX=snakeHead.x();
    int headY=snakeHead.y();

    if(headX>360)
    {
        leftTop=QPointF(0,headY);
    }
    else
    {
        leftTop=snakeHead.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++)
        {
            if(snakeList.at(i)==snakeList.at(j))
            {
                return true;
            }
        }
    }
    return false;
}

void GameRoom::createFood()
{
    foodRect=QRectF(qrand()%(400/kSnakeNodeWidth)*kSnakeNodeWidth,
                    qrand()%(400/kSnakeNodeHeight)*kSnakeNodeHeight,kSnakeNodeWidth,kSnakeNodeHeight);
}