一、新建一个Qt项目
新建Qt Widgets Application,项目名称为HappySnake,基类选择QWidget,类名默认
二、添加要用到的头文件
#include <QKeyEvent>#include <QRectF>#include <QPainter>#include <QPen>#include <QBrush>#include <QDebug>#include <QTimer>#include <QTime>
三、写类声明信息
贪吃蛇的本体使用小方框来代替使用QList类来保存贪吃蛇的本体使用定时器来设定刷新的时间使用随机函数生成奖励的节点使用paintEvent来进行绘图keyPressEvent来监测按键的按下,控制贪吃蛇的移动class Widget : public QWidget{Q_OBJECTpublic:explicit Widget(QWidget *parent = 0);~Widget();protected:void paintEvent(QPaintEvent *);void keyPressEvent(QKeyEvent *);private:void addTopRectF();void addDownRectF();void addLeftRectF();void addRightRectF();void deleteLastRectF();bool snakeStrike();enum Move{Left,Right,Up,Down};protected slots:void timeOut();void rewardTimeOut();private:Ui::Widget *ui;QList<QRectF> snake;//贪吃蛇本体int snakeNodeWidth = 10;int snakeNodeHeight = 10;QTimer *timer;QTimer *rewardTimer;int time = 100;int moveFlage = Up;bool gameOver = false;bool gameStart = false;QList<QRectF> rewardNode;//奖励节点};
四、对类函数的实现
构造函数
Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget){ui->setupUi(this);resize(480,500);//设置窗体背景色为黑色setStyleSheet("QWidget{background:black}");setWindowOpacity(0.8);//设置窗口的透明度snake.append(QRectF(200,500,snakeNodeWidth,snakeNodeHeight));addTopRectF();addTopRectF();//首先生成一个奖励节点rewardNode.append(QRectF(100,100,snakeNodeWidth,snakeNodeWidth));timer = new QTimer;connect(timer, SIGNAL(timeout()),this,SLOT(timeOut()));//timer->start(time);rewardTimer = new QTimer;connect(rewardTimer,SIGNAL(timeout()),this,SLOT(rewardTimeOut()));//rewardTimer->start(time*30);}Widget::~Widget(){delete ui;}
界面刷新
void Widget::timeOut(){int flage = 1;for(int i=0; i<rewardNode.length(); i++){if(rewardNode.at(i).contains(snake.at(0).topLeft()+QPointF(snakeNodeWidth/2,snakeNodeHeight/2))){//if(snake.at(0).contains(rewardNode.at(i).x()+rewardNode.at(i).width()/2,rewardNode.at(i).y()+rewardNode.at(i).height()/2)){if(rewardNode.at(i).width()>snakeNodeWidth){//额外奖励flage += 2;}flage++;//正常奖励rewardNode.removeAt(i);break;}}while(flage--){switch (moveFlage) {case Up:addTopRectF();break;case Down:addDownRectF();break;case Right:addRightRectF();break;case Left:addLeftRectF();break;default:break;}}deleteLastRectF();update();}
随机奖励的生成
//随机奖励void Widget::rewardTimeOut(){qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));if(rewardNode.length() > 5){rewardNode.removeAt(qrand()%5);}rewardNode.append(QRectF(qrand()%(this->width()/20)*20,qrand()%(this->height()/20)*20,snakeNodeWidth,snakeNodeWidth));if(qrand()%5 == 3){rewardNode.append(QRectF(qrand()%(this->width()/20)*20-5,qrand()%(this->height()/20)*20-5,snakeNodeWidth*2,snakeNodeWidth*2));}}
移动
//向上移动void Widget::addTopRectF(){if(snake.at(0).y()-snakeNodeHeight < 0){snake.insert(0,QRectF(QPointF(snake.at(0).x(),this->height()-snakeNodeHeight),QPointF(snake.at(0).x()+snakeNodeWidth,this->height())));}else{snake.insert(0,QRectF(snake.at(0).topLeft()+QPointF(0,-snakeNodeHeight),snake.at(0).topRight()));}}//向下移动void Widget::addDownRectF(){if(snake.at(0).y()+snakeNodeHeight*2 > this->height()){snake.insert(0,QRectF(QPointF(snake.at(0).x(),snakeNodeHeight),QPointF(snake.at(0).x()+snakeNodeWidth,0)));}else{snake.insert(0,QRectF(snake.at(0).bottomLeft(),snake.at(0).bottomRight()+QPointF(0,snakeNodeHeight)));}}//向左移动void Widget::addLeftRectF(){if(snake.at(0).x()-snakeNodeWidth < 0){snake.insert(0,QRectF(QPointF(this->width()-snakeNodeWidth,snake.at(0).y()),QPointF(this->width(),snake.at(0).y()+snakeNodeHeight)));}else{snake.insert(0,QRectF(snake.at(0).topLeft()+QPointF(-snakeNodeWidth,0),snake.at(0).bottomLeft()));}}//向右移动void Widget::addRightRectF(){if(snake.at(0).x()+snakeNodeWidth*2 > this->width()){snake.insert(0,QRectF(QPointF(0,snake.at(0).y()),QPointF(snakeNodeWidth,snake.at(0).y()+snakeNodeHeight)));}else{snake.insert(0,QRectF(snake.at(0).topRight(),snake.at(0).bottomRight()+QPointF(snakeNodeWidth,0)));}}//删除结尾数据void Widget::deleteLastRectF(){snake.removeLast();}
绘图
//绘图void Widget::paintEvent(QPaintEvent *event){QPainter painter(this);QPen pen;QBrush brush;QFont font("方正舒体",12,QFont::ExtraLight,false);//反锯齿painter.setRenderHint(QPainter::Antialiasing);pen.setColor(Qt::black);brush.setColor(Qt::green);brush.setStyle(Qt::SolidPattern);painter.setPen(pen);painter.setBrush(brush);for(int i=0; i<snake.length(); i++){painter.drawRect(snake.at(i));}brush.setColor(Qt::red);painter.setBrush(brush);for(int i=0; i<rewardNode.length(); i++){painter.drawEllipse(rewardNode.at(i));}pen.setColor(Qt::white);painter.setPen(pen);painter.setFont(font);painter.drawText(20,20,QString("当前得分:")+QString("%1").arg(snake.length()));if(snakeStrike()){QFont font("方正舒体",30,QFont::ExtraLight,false);painter.setFont(font);painter.drawText((this->width()-300)/2,(this->height()-30)/2,QString("GAME OVER!"));timer->stop();rewardTimer->stop();gameOver = true;}QWidget::paintEvent(event);}
按键事件
void Widget::keyPressEvent(QKeyEvent *event){switch(event->key()){case Qt::Key_Up:if(moveFlage != Down){moveFlage = Up;}break;case Qt::Key_Down:if(moveFlage != Up){moveFlage = Down;}break;case Qt::Key_Right:if(moveFlage != Left){moveFlage = Right;}break;case Qt::Key_Left:if(moveFlage != Right){moveFlage = Left;}break;case Qt::Key_Enter:case Qt::Key_Return:if(gameOver){snake.clear();rewardNode.clear();moveFlage = Up;snake.append(QRectF(200,500,snakeNodeWidth,snakeNodeHeight));addTopRectF();addTopRectF();//首先生成一个奖励节点rewardNode.append(QRectF(100,100,snakeNodeWidth,snakeNodeWidth));timer->start(time);rewardTimer->start(time*30);gameOver = false;}break;case Qt::Key_Space:if(gameStart && !gameOver){timer->start(time);rewardTimer->start(time*30);gameStart = false;}else if(!gameStart && !gameOver){timer->stop();rewardTimer->stop();gameStart = true;}break;default:break;}}
判断蛇身是否相撞
//判断蛇头是否和蛇身相撞bool Widget::snakeStrike(){for(int i=0; i<snake.length(); i++){for(int j=i+1; j<snake.length(); j++){if(snake.at(i) == snake.at(j)){return true;}}}return false;}
五、结束
实现的效果:
提供源码在博客的资源中,Qt5.6版本正常运行。
点击下载源码
总结:
只是简单的使用了paintevent进行绘图,基本都是简单的对Qt的一些常用类的使用,对面向对象的编程应用的不是很好,更偏向于面向过程,所以完全可以改成C语言在Linux下实现,思路都是相同的。
如果觉得《QT实现简单的贪吃蛇小游戏》对你有帮助,请点赞、收藏,并留下你的观点哦!