Qt製作貪吃蛇(二)

這篇文章內容是參考https://blog.csdn.net/sinan1995/article/details/81671311

 

這篇文章主要怎樣產生食物,並可以被蛇遲到

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "snake.h"
#include <QPaintEvent>
#include <QPainter>
#include <QBrush>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

public:
    void paintEvent(QPaintEvent *event);
    void keyPressEvent(QKeyEvent *event);

public:
    void createFood();
    bool hasEatFood();       //是否吃到食物

public:
    QTimer *snakeMoveTimer;
    QTimer *createFoodTimer;
    QTimer *listenningTimer;      //監聽器,高頻率判斷某事件是否發生,頻率越高可能比較消耗性能
    void initTimer();             //初始化計時器,將計時器的創建放入這個函數中

public:
    Snake snake;
    QList<QRectF> food;

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

定義了一個食物屬性,還有一個創建食物的函數。定時器createFoodTimer用於間隔固定的時間創建一個食物,即執行createFood函數。當時調試的時候,發現如果蛇跑了很快(按住方向鍵不鬆手),有的時候吃不到食物,爲止我又加了一個定時器listenningTimer,我把它取名叫做監聽器,監聽某個時候是否吃到食物,將時間縮的更短,但性能消耗更大。

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTimer>
#include <QTime>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    resize(480, 500);

    snake.initBody();

    snake.move(this->width(),this->height());   //程序一啓動就要走一步,然後每隔固定時間走一步
    createFood();   //程序一啓動就創建一個food

    initTimer();
}

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

void MainWindow::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);  //開啓抗鋸齒

    QPen pen;
    pen.setColor(Qt::black);
    painter.setPen(pen);

    QBrush brush;
    brush.setColor(Qt::green);
    brush.setStyle(Qt::SolidPattern);
    painter.setBrush(brush);

    for(int i=0;i<snake.body.size();i++){
        painter.drawRect(snake.body.at(i));
    }

    brush.setColor(Qt::red);
    painter.setBrush(brush);

    for(int i=0;i<food.size();i++){
        painter.drawEllipse(food.at(i));
    }


    update();
}

void MainWindow::keyPressEvent(QKeyEvent *event)
{
    switch (event->key()) {
        case Qt::Key_Up:
            snake.moveUp(this->height());
            break;
        case Qt::Key_Down:
            snake.moveDown(this->height());
            break;
        case Qt::Key_Left:
            snake.moveLeft(this->width());
            break;
        case Qt::Key_Right:
            snake.moveRight(this->width());
            break;
    }
}

void MainWindow::createFood()
{
    qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
//    if(food.size()>5){        //可以選擇消除存在的食物,以至於讓界面上同時存在的食物不會那麼多
//        food.removeAt(qrand()%5);
//    }
    food.append(QRectF(qrand()%(this->width()/20)*20,qrand()%(this->height()/20)*20,snake.width,snake.height));
    if(qrand()%5==3){
         food.append(QRectF(qrand()%(this->width()/20)*20-5,qrand()%(this->height()/20)*20-5,2*snake.width,2*snake.height));
    }
}

bool MainWindow::hasEatFood()
{
    for(int i=0;i<food.size();i++){
        if(food.at(i).contains(snake.body.at(0).topLeft()+QPointF(snake.width/2,snake.height/2))){
            food.removeAt(i);

            snake.addNode(this->width(),this->height());

            qDebug()<<"eat food";
            return true;
        }
    }
    return false;
}

void MainWindow::initTimer()
{
//開啓定時器,讓蛇自動走起來,並監聽吃食物
    snakeMoveTimer = new QTimer(this);
    snakeMoveTimer->setInterval(500); //每200毫秒走一步
    connect(snakeMoveTimer,&QTimer::timeout,this,[=]{
        snake.move(this->width(),this->height());
    });
    snakeMoveTimer->start();
//每隔一定時間創建出一個food
    createFoodTimer = new QTimer(this);
    createFoodTimer->setInterval(1000);
    connect(createFoodTimer,&QTimer::timeout,this,[=]{
        createFood();
    });
    createFoodTimer->start();
//創建一個監聽器
    listenningTimer = new QTimer(this);
    listenningTimer->setInterval(20);   //0.02s監聽一次
    connect(listenningTimer,&QTimer::timeout,this,[=]{
        hasEatFood();
    });
    listenningTimer->start();
}

運行效果

Snake類變動

我在snake多加了一個函數addNode,用於當遲到了食物就長度就增加1

#ifndef SNAKE_H
#define SNAKE_H

#include <QObject>
#include <QList>

class Snake : public QObject
{
    Q_OBJECT
public:
    explicit Snake(QObject *parent = nullptr);
public:
    enum Dir{Up, Down, Left, Right};

public:
    int moveDir = Dir::Up;
    int width=10;
    int height=10;
    QList<QRectF> body;

public:
    //節點個數,初始頭的位置,朝向(默認爲上)
    void initBody(int nodeNum=3,QPointF topLeft=QPointF(400,400),Dir dir=Dir::Up,int nodeWidth=10,int nodeHeight=10);
private:
    void addNodeUp(int);
    void addNodeDown(int);
    void addNodeLeft(int);
    void addNodeRight(int);
public:
    void moveUp(int);
    void moveDown(int);
    void moveRight(int);
    void moveLeft(int);
    void move(int,int); //沿着當前的方向移動
    void addNode(int,int);

signals:

public slots:
};

#endif // SNAKE_H
void Snake::addNode(int windowWidth,int windowHeight)
{
    switch (moveDir) {
    case Dir::Up:
        addNodeUp(windowHeight);
        break;
    case Dir::Down:
        addNodeDown(windowHeight);
        break;
    case Dir::Left:
        addNodeLeft(windowWidth);
        break;
    case Dir::Right:
        addNodeRight(windowWidth);
        break;
    }
}

可以改進的地方

關於產生食物,可以不讓食物產生的地方在蛇身上,也不要出現在已經有食物的地方

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章