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

可以改进的地方

关于产生食物,可以不让食物产生的地方在蛇身上,也不要出现在已经有食物的地方

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