溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

QT如何實(shí)現(xiàn)貪吃蛇游戲

發(fā)布時(shí)間:2021-05-18 10:29:23 來(lái)源:億速云 閱讀:414 作者:小新 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要介紹了QT如何實(shí)現(xiàn)貪吃蛇游戲,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

為了熟悉QT的相關(guān)知識(shí),我用了大約8個(gè)小時(shí)的時(shí)間用QT再次寫(xiě)了一遍貪吃蛇。

因?yàn)镼T的機(jī)制和平時(shí)寫(xiě)的程序流程不同,所以程序中可能沒(méi)有遵守代碼規(guī)范。

運(yùn)行效果:

QT如何實(shí)現(xiàn)貪吃蛇游戲

程序內(nèi)除了實(shí)現(xiàn)貪吃蛇的基本功能外,還添加了記錄得分、調(diào)節(jié)游戲速度、重新開(kāi)始游戲等功能。

游戲內(nèi)容使用QPainter類進(jìn)行繪制。

編譯環(huán)境:

Windows Qt 5.9.0 Qt Creator 4.3.0

思路:

數(shù)組存儲(chǔ)蛇節(jié)點(diǎn)坐標(biāo)的貪吃蛇游戲思路。

因?yàn)榫帉?xiě)過(guò)程中使用了分文件編寫(xiě),且QT框架的其他部分較多,這里僅展示程序?qū)崿F(xiàn)主要代碼。

代碼:

MainWindow.h 主窗口類頭文件

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QPainter>     //畫(huà)家類
#include "snake.h"      //蛇類
#include <QKeyEvent>    //鍵盤(pán)事件
#include "food.h"       //食物類
#include <QTimer>       //定時(shí)器類

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

    //繪圖事件
    void paintEvent(QPaintEvent *);

    //游戲結(jié)束的情況
    void GameOver();

private:
    Ui::Widget *ui;

    Snake snake;        //蛇對(duì)象
    char key = 'd';     //接收鍵值,初始向右
    Food food;          //食物對(duì)象
    //創(chuàng)建定時(shí)器
    QTimer *timer = new QTimer(this);
    bool gameflag = false;//游戲結(jié)束標(biāo)記
    int score = 0;      //記錄得分
    int timerspeed = 200; //定時(shí)器速度
    bool bugflag = false; //用于解決操控過(guò)快導(dǎo)致撞死自己的bug的標(biāo)志

    //鍵盤(pán)事件,改變鍵值
    void keyPressEvent(QKeyEvent *ev);
};

#endif // WIDGET_H

MainWindow.cpp函數(shù)實(shí)現(xiàn)

#include "MainWindow.h"
#include "ui_widget.h"
#include <QLabel>
#include <QPushButton>

//主窗口構(gòu)造函數(shù)
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
{
    ui->setupUi(this);      //初始化出.ui界面

    //一個(gè)格子寬高25像素,地圖寬高600像素,每行有24個(gè)格子

    //設(shè)置固定窗口大小
    setFixedSize(1000,600);

    //設(shè)置得分標(biāo)簽控件的屬性
    ui->label->setFont(QFont("黑體", 20, QFont::Bold, false));

    //設(shè)置游戲速度標(biāo)簽內(nèi)容
    ui->label_2->setFont(QFont("楷體", 16, QFont::Bold, false));
    ui->label_2->setText("游戲速度:");

    //滑動(dòng)條控件,這里將數(shù)值按一定比例放大縮小
    ui->horizontalSlider->setValue(200 >> 2);

    //監(jiān)聽(tīng)滑動(dòng)條控件滑動(dòng)時(shí),改變定時(shí)器速度為滑動(dòng)條的值
    connect(ui->horizontalSlider,QSlider::valueChanged,[=]()
    {
        timerspeed = ui->horizontalSlider->value() << 2;
    });

    //設(shè)置重新開(kāi)始按鈕屬性和內(nèi)容
    ui->pushButton_3->setFont(QFont("黑體",12));
    ui->pushButton_3->setText("重新開(kāi)始");

    //監(jiān)聽(tīng)重新開(kāi)始按鈕
    connect(ui->pushButton_3,QPushButton::clicked,[=]()
    {
        snake.Reset();      //重置蛇
        score = 0;          //得分清0
        key = 'd';          //key值向右
        timerspeed = 200 << 2;//重置游戲速度
        timer->start(timerspeed);//重置定時(shí)器
        ui->horizontalSlider->setValue(200 >> 2);//重置滑動(dòng)條
        gameflag = false;   //重置游戲結(jié)束標(biāo)志
    });

    //開(kāi)啟定時(shí)器
    timer->start(timerspeed);

    //監(jiān)聽(tīng)定時(shí)器的信號(hào),執(zhí)行表達(dá)式內(nèi)容
    connect(timer,&QTimer::timeout,[=]()
    {
        timer->start(timerspeed); //調(diào)整定時(shí)器的速度

        snake.Move(key);    //蛇移動(dòng)函數(shù)

        //吃到食物的情況
        (food.getfoodX() == snake.snakevec.at(0).x && food.getfoodY() == snake.snakevec.at(0).y) ?
        score++, food.randfood():    //得分+1,隨機(jī)產(chǎn)生一個(gè)食物坐標(biāo)
        snake.snakevec.pop_back();   //刪除蛇尾

        GameOver();    //游戲失敗的情況

        update();      //調(diào)用繪圖函數(shù)

        //更新標(biāo)簽控件的文本內(nèi)容
        ui->label->setText(QString("得分:%1").arg(score));
    });
}

//游戲失敗情況
void Widget::GameOver()
{
    //撞墻失敗
    if(snake.snakevec.at(0).x >= 24 * 25 || snake.snakevec.at(0).x < 0 ||
       snake.snakevec.at(0).y < 0 || snake.snakevec.at(0).y >= 24 * 25)
    {
        gameflag = true;
        timer->stop();      //暫停定時(shí)器
        return;
    }

    //撞自己失敗
    for(int i = 1; i < snake.snakevec.size(); i++)
    {
        if(snake.snakevec.at(0).x == snake.snakevec.at(i).x &&
           snake.snakevec.at(0).y == snake.snakevec.at(i).y)
            gameflag = true, timer->stop();
    }
}


//繪圖事件
void Widget::paintEvent(QPaintEvent *)
{
    //創(chuàng)建畫(huà)家對(duì)象,指定繪圖設(shè)備為this主窗口
    QPainter painter(this);

    //設(shè)置畫(huà)刷為紅色
    QBrush brush2(Qt::red);
    //讓畫(huà)家使用畫(huà)刷
    painter.setBrush(brush2);
    //畫(huà)食物
    painter.drawRect(QRect(food.getfoodX(),food.getfoodY(),25,25));

    //設(shè)置畫(huà)刷為黑色
    QBrush brush3(Qt::blue);
    painter.setBrush(brush3);

    //遍歷蛇坐標(biāo)容器,畫(huà)出代表蛇身的矩形
    for(auto snakenodei : snake.snakevec)
        //蛇頭畫(huà)圓形
        (snakenodei.x == snake.snakevec.at(0).x &&
         snakenodei.y == snake.snakevec.at(0).y) ?
        //蛇頭畫(huà)圓形
        painter.setRenderHint(QPainter::Antialiasing),  //用抗鋸齒畫(huà)圓
        painter.drawEllipse(QPoint(snakenodei.x + 12,snakenodei.y + 12),12,12):
        //蛇身畫(huà)矩形
        painter.drawRect(QRect(snakenodei.x,snakenodei.y,25,25));

    bugflag = false;    //在畫(huà)出蛇之后將標(biāo)志設(shè)為假

    //設(shè)置畫(huà)刷為黑色
    QBrush brush4(QColor(128, 64, 0));
    painter.setBrush(brush4);

    //畫(huà)出墻壁
    for(int i = 0; i < 24; i++)
          painter.drawRect(QRect(25 * 25, i * 25, 25, 25));

    //游戲結(jié)束時(shí)的繪圖
    if(gameflag)
    {   //設(shè)置文字屬性
        QFont font("楷體", 80, QFont::Bold, false);
        painter.setFont(font);      //使用字體
        painter.drawText(QRect(240, 200, 1000, 500), "游戲結(jié)束");   //畫(huà)出游戲結(jié)束文字
    }
}

//鍵盤(pán)事件,改變貪吃蛇移動(dòng)方向
void Widget::keyPressEvent(QKeyEvent *ev)
{
    if(bugflag)     //bug標(biāo)志為真直接返回
        return;

    switch (ev->key())
    {
    case Qt::Key_W:
        if(key == 's') break;   //按下與當(dāng)前方向相反按鍵時(shí)break
        key = 'w';
        bugflag = true; break;        //按鍵之后將標(biāo)志設(shè)為真
    case Qt::Key_S:
        if(key == 'w') break;
        key = 's';
        bugflag = true; break;
    case Qt::Key_A:
        if(key == 'd') break;
        key = 'a';
        bugflag = true; break;
    case Qt::Key_D:
        if(key == 'a') break;
        key = 'd';
        bugflag = true; break;
    case Qt::Key_Space:     //空格鍵暫停,這里有點(diǎn)問(wèn)題
        timer->stop(); break;
    default:                //其他鍵重啟定時(shí)器
        timer->start(timerspeed);
    }
}

//析構(gòu)
Widget::~Widget()
{
    delete ui;
}

snake.h 蛇類頭文件

#ifndef SNAKE_H
#define SNAKE_H

#include <QWidget>
#include <QVector>      //Qt動(dòng)態(tài)數(shù)組類

class Snake : public QWidget
{
    Q_OBJECT
private:
    //蛇坐標(biāo)結(jié)構(gòu)
    struct  Snakecoor
    {
        int x;
        int y;
    };

public:
    explicit Snake(QWidget *parent = nullptr);

    //蛇坐標(biāo)容器
    QVector<Snakecoor> snakevec;

    //蛇移動(dòng)主要函數(shù)
    void Move(char key);

    //根據(jù)key值確定蛇的移動(dòng)方向
    void DeteDirMove(char key, Snakecoor &nexthead);

    //重置蛇
    void Reset();

signals:

public slots:
};

#endif // SNAKE_H

snake.cpp 蛇類函數(shù)實(shí)現(xiàn)

#include "snake.h"

//構(gòu)造函數(shù)初始化一條蛇
Snake::Snake(QWidget *parent) : QWidget(parent)
{
    Snakecoor snakenode;            //臨時(shí)結(jié)構(gòu)變量用于創(chuàng)建蛇
    for (int i = 5; i >= 0; i--) //從右向左創(chuàng)建5節(jié)蛇身,容器的第一個(gè)元素為蛇頭
    {
        snakenode.x = 25 * 8 + i * 25;//每個(gè)格子寬25像素
        snakenode.y = 25 * 8;
        snakevec.push_back(snakenode);//將蛇節(jié)點(diǎn)插入到數(shù)組中
    }
}

//確定蛇的移動(dòng)方向,確定新蛇頭的坐標(biāo)位置
inline void Snake::DeteDirMove(char key, Snakecoor &nexthead)
{
    switch (key)
    {
    case 'w':
        //新蛇頭坐標(biāo)根據(jù)舊蛇頭坐標(biāo)改變
        nexthead.x = snakevec.front().x;
        nexthead.y = snakevec.front().y - 25;
        break;
    case 's':
        nexthead.x = snakevec.front().x;
        nexthead.y = snakevec.front().y + 25;
        break;
    case 'a':
        nexthead.x = snakevec.front().x - 25;
        nexthead.y = snakevec.front().y;
        break;
    case 'd':
        nexthead.x = snakevec.front().x + 25;
        nexthead.y = snakevec.front().y;
    }
}

//蛇移動(dòng)主要函數(shù)
void Snake::Move(char key)
{
    Snakecoor nexthead;  //創(chuàng)建一個(gè)新的蛇頭

    DeteDirMove(key, nexthead);  //確定新蛇頭的位置

    snakevec.insert(snakevec.begin(), nexthead);    //將新蛇頭插入到容器頭部
}

//重置蛇函數(shù)
void Snake::Reset()
{
    snakevec.clear();   //清空容器

    //初始化蛇
    Snakecoor snakenode;
    for (int i = 5; i >= 0; i--)
    {
        snakenode.x = 25 * 8 + i * 25;
        snakenode.y = 25 * 8;
        snakevec.push_back(snakenode);
    }
}

food.h 食物類頭文件

#ifndef FOOD_H
#define FOOD_H

#include <QWidget>

class Food : public QWidget
{
    Q_OBJECT
public :
    int food_x = 0;     //食物坐標(biāo)
    int food_y = 0;

public:
    explicit Food(QWidget *parent = nullptr);

    void randfood();    //隨機(jī)產(chǎn)生食物坐標(biāo)
    int getfoodX();     //返回食物坐標(biāo)
    int getfoodY();

signals:

public slots:
};

#endif // FOOD_H

food.cpp 食物類函數(shù)實(shí)現(xiàn)

#include "food.h"
#include <ctime>

Food::Food(QWidget *parent) : QWidget(parent)
{
    randfood();     //創(chuàng)建對(duì)象時(shí)產(chǎn)生就一個(gè)隨機(jī)坐標(biāo)

}

//隨機(jī)產(chǎn)生食物坐標(biāo)
void Food::randfood()
{
    srand((unsigned)time(NULL));
    food_x = (rand() % 24) * 25;
    food_y = (rand() % 24 )* 25;
}

//獲取食物的坐標(biāo)
int Food::getfoodX()
{
    return food_x;
}

int Food::getfoodY()
{
    return food_y;
}

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“QT如何實(shí)現(xiàn)貪吃蛇游戲”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來(lái)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

qt
AI