QT实现简单的贪吃蛇小游戏

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

猜你喜欢

转载自blog.csdn.net/sinan1995/article/details/81671311