一、新建一个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_OBJECT
public:
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下实现,思路都是相同的。