这篇文章内容是参考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;
}
}
可以改进的地方
关于产生食物,可以不让食物产生的地方在蛇身上,也不要出现在已经有食物的地方