• Qt6_贪吃蛇Greedy Snake


    贪吃蛇Greedy Snake

    1分析

    首先这是一个贪吃蛇界面,由一个长方形边框和一只贪吃蛇组成

    image-20230905161147724

    默认开局时,贪吃蛇身体只有3个小方块,使用画笔画出

    1.1如何移动

    对于蛇的移动,有2种方法

    1. 在一定时间范围内(定时器),未对游戏做出操作(前后左右移动),则整个身体向面朝方向移动一格
    2. 在一定时间范围内(定时器),未对游戏做出操作(前后左右移动),则身体最前面加上一格方块,身体最后面减去一个方块

    这里使用第2种方法

    如图,有4个坐标,AC分别是原蛇的头部方格的两个坐标

    则新产生的方格的B点为(x1,y1-方格高度);D点(x3,y3-方格高度)

    image-20230905180018710

    注意

    向某个方向增加不能无限增加下去,当触碰到顶部时,我们可以设置条件:

    1. 死亡
    2. 穿过从另一个方向开始

    这里我们采用第2种方式

    1.2向上

    如图,此时BD点已经超过x轴,即高度为0的位置

    image-20230905180927106

    因此我们可以判断:当蛇头部的方格A/C的高度 - 1个方格的高度 < 0 时,则从底部开始进入

    image-20230905231105665

    • 移动前:x3=x1+蛇宽度;y3=y1

    • 移动后:x2=x1,y2=窗口高度-蛇宽度;x4=x2+蛇宽度,y4=y2

    1.3向下

    同理,向下走只要最下面增加,最上面减少即可

    image-20230905231120101

    • 移动前:x4=x2+蛇宽度;y2=y4

    • 移动后:x1=x2,y1=0;x3=x1+蛇宽度,y3=蛇高度

    1.4向左

    • 移动前:x3=x2+蛇宽;y3=y2+蛇高

    • 移动后:x1=x2-蛇宽,y1=y2;x4=x2,y4=y3

    image-20230905235603773

    穿越

    • x2=窗口宽度-蛇宽,y2=y1
    • x3=窗口宽度,y3=y4

    image-20230907123806011

    1.5向右

    • 移动前:x4=x1+蛇宽;y4=y1+蛇高

    • 移动后:x2=x1+蛇宽,y2=y1;x3=x4+蛇宽,y3=y4

    image-20230906000046738

    穿越

    • x2=0,y2=y1;
    • x3=蛇宽,y3=y4

    image-20230907123143492

    2如何成长

    在界面的不同地方会默认刷新出一个球,蛇吃了这个球身体就会增加一格,同时球消失刷新出现在其他地方

    image-20230905162217248

    判断球是否被吃掉:即判断蛇的身体是否与球重合,如果重合,增加身体1,同时刷新球出现的位置

    3代码

    widget.h

    #ifndef WIDGET_H
    #define WIDGET_H
    
    #define OUTTIME 100 //超时时间
    #define SNAKE_WIDTH 20  //蛇的一个方格宽度
    #define SNAKE_HEIGHT 20 //蛇的一个方格高度
    #include 
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include 
    
    /*
        0.创建蛇
            要求:可以实现前面删除后面增加,可以用LIST链表
        1.按键处理
        2.使用定时器
           2.1关联信号槽
           2.2启动定时器
           2.3实现对应的超时处理(timeOut)函数
        3.渲染图像
    */
    
    QT_BEGIN_NAMESPACE
    namespace Ui { class Widget; }
    QT_END_NAMESPACE
    //定义方向
    enum Direction
    {
        LEFT,
        RIGHT,
        UP,
        DOWN
    };
    class Widget : public QWidget
    {
        Q_OBJECT
    public:
        Widget(QWidget *parent = nullptr);
        ~Widget();
    protected:
        //按键处理
        void keyPressEvent(QKeyEvent *event);
        //添加头部
        void addTOP();
        void addBUTOM();
        void addLEFT();
        void addRIGHT();
        //绘制界面
        void paintEvent(QPaintEvent *event);
        //删除尾部
        void deleLAST();
        //初始化食物
        void initFood();
        //判断是否碰撞
        bool isIntersect();
    private:
        Ui::Widget *ui;
        int moveFlag = UP;  //方向标志
        bool gameStatu = false;//游戏状态
        //bool isIntersect = false;
        //定时器
        QTimer *timer;
        //事物
        QRectF food;
        //创建蛇
        QList snake;
    protected slots:
        void timeOut();//超时函数
    };
    #endif // WIDGET_H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75

    widget.cpp

    #include "widget.h"
    #include "ui_widget.h"
    
    Widget::Widget(QWidget *parent)
        : QWidget(parent)
        , ui(new Ui::Widget)
    {
        ui->setupUi(this);
        this->resize(450,300);
        //使用定时器
        timer = new QTimer();
        //发出信号
        //连接信号
        connect(timer,SIGNAL(timeout()),this,SLOT(timeOut()));
    
        //初始化蛇
        QRectF rect(this->width()/2,this->height()/2,SNAKE_WIDTH,SNAKE_HEIGHT);
        snake.append(rect); //蛇身+1
        addTOP();   //蛇身+1
        addTOP();
    
        //初始化食物
        initFood();
    }
    
    Widget::~Widget()
    {
        delete ui;
    }
    
    //按键绑定:控制方向
    void Widget::keyPressEvent(QKeyEvent *event)
    {
        switch(event->key())
        {
        case Qt::Key_Up:
            if(moveFlag != DOWN)
            {
                moveFlag = UP;
            }
            break;
        case Qt::Key_Down:
            if(moveFlag != UP)
            {
                moveFlag = DOWN;
            }
            break;
        case Qt::Key_Left:
            if(moveFlag != RIGHT)
            {
                moveFlag = LEFT;
            }
            break;
        case Qt::Key_Right:
            if(moveFlag != LEFT)
            {
                moveFlag = RIGHT;
            }
            break;
        case Qt::Key_Space:
            if(!gameStatu)
            {
                gameStatu = true;
                //启动定时器
                timer->start(OUTTIME);
            }
            else
            {
                gameStatu = false;
                timer->stop();
            }
            break;
        default:
            return;
            break;
        }
    }
    
    //顶部增加
    void Widget::addTOP()
    {
        QPointF leftTop;    //左上点
        QPointF rightBotom; //右下点
    
        if(snake[0].y() - SNAKE_HEIGHT < 0 )    //如果超过顶部
        {
            leftTop = QPoint(snake[0].x(),this->height() - SNAKE_HEIGHT);
            rightBotom = QPoint(snake[0].x() + SNAKE_WIDTH,this->height());
        }
        else    //未超过顶部
        {
            leftTop = QPointF(snake[0].x(),snake[0].y() - SNAKE_HEIGHT);
            rightBotom = snake[0].topRight();
        }
        snake.insert(0,QRectF(leftTop,rightBotom));
    }
    
    void Widget::addBUTOM()
    {
        QPointF leftTop;
        QPointF rightBotom;
    
        if(snake[0].y() + 2*SNAKE_HEIGHT > this->height() )    //如果超过底部
        {
            leftTop = QPointF(snake[0].topLeft().x(),0);
                  //                    原x           0
            rightBotom = QPointF(snake[0].bottomRight().x(),SNAKE_HEIGHT);
                        //          右下x+蛇宽               蛇高
        }
        else    //未超过底部
        {
            leftTop = snake[0].bottomLeft();
            rightBotom = snake[0].bottomRight()+QPointF(0,SNAKE_HEIGHT);
        }
        snake.insert(0,QRectF(leftTop,rightBotom));
    }
    
    void Widget::addLEFT()
    {
        QPointF leftTop;
        QPointF rightBotom;
    
        if(snake[0].x()-SNAKE_WIDTH < 0 )    //超过边缘
        {
            leftTop = QPointF(this->width()-SNAKE_WIDTH,snake[0].topLeft().y());
                //              窗口宽-蛇宽                  左上原y不变
            rightBotom = QPointF(this->width(),snake[0].bottomRight().y());
                //              窗口宽                     右下原y不变
        }
        else    //未超过
        {
            leftTop = QPointF(snake[0].topLeft().x()-SNAKE_WIDTH,snake[0].topLeft().y());
                   //               左上x-蛇宽                          左上原y不变
            rightBotom = QPointF(snake[0].bottomRight().x()-SNAKE_WIDTH,snake[0].bottomRight().y());
                    //                  右下x-蛇宽                      右下原y不变
        }
        snake.insert(0,QRectF(leftTop,rightBotom));
    }
    
    void Widget::addRIGHT()
    {
        QPointF leftTop;
        QPointF rightBotom;
    
        if(snake[0].x()+SNAKE_WIDTH*2 > this->width() )    //超过边缘
        {
            leftTop = QPointF(0,snake[0].topLeft().y());
                //           0      左上原y不变
            rightBotom = QPointF(SNAKE_WIDTH,snake[0].bottomRight().y());
                //              蛇宽                     右下原y不变
        }
        else    //未超过边缘
        {
            leftTop = QPointF(snake[0].topLeft().x()+SNAKE_WIDTH,snake[0].topLeft().y());
                //               左上x-蛇宽                          左上原y不变
            rightBotom = QPointF(snake[0].bottomRight().x()+SNAKE_WIDTH,snake[0].bottomRight().y());
                //                  右下x-蛇宽                      右下原y不变
        }
        snake.insert(0,QRectF(leftTop,rightBotom));
    }
    
    //绘制界面
    void Widget::paintEvent(QPaintEvent *event)
    {
        QPainter painter(this);
        QPen pen;//画笔
        QBrush brush;//画刷
    
        //加载背景图片
        QPixmap pix;
        pix.load(":/background/bg_1.jpg");
        painter.drawPixmap(0,0,pix.width(),pix.height(),pix);
    
        //绘制蛇
        pen.setColor(Qt::black);    //设定画笔颜色
        brush.setColor(Qt::darkMagenta);//画刷颜色
        brush.setStyle(Qt::SolidPattern);//画刷风格
        painter.setPen(pen);    //画家配置画笔
        painter.setBrush(brush);//画家配置画刷
    
        for(int i=0;iwidth()/2-120,
                     this->height()/2,
                     QString("GAME OVER!"));
            timer->stop();
        }
    }
    
    //去尾
    void Widget::deleLAST()
    {
        snake.removeLast();
    }
    
    // 初始化食物
    void Widget::initFood()
    {								//QRandomGenerator::global()->generate()随机生成数字
        food = QRectF(QRandomGenerator::global()->generate()%(this->width()/20)*20,
                      QRandomGenerator::global()->generate()%(this->height()/20)*20,
                      SNAKE_WIDTH,SNAKE_HEIGHT);
    }
    
    //是否碰撞
    bool Widget::isIntersect()
    {
        for(int i=1;i
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265

    4效果

    //重新初始化食物,即令其刷新位置
    initFood();
    }
    while(count–)
    {
    switch (moveFlag)
    {
    case UP:
    addTOP();
    break;
    case DOWN:
    addBUTOM();
    break;
    case LEFT:
    addLEFT();
    break;
    case RIGHT:
    addRIGHT();
    break;
    default:
    return;
    break;
    }
    }
    deleLAST();
    update(); //重新绘制,即更新图像
    }

    
    ## 4效果
    
    ![greedy_snake](https://img-blog.csdnimg.cn/img_convert/709a852d84a10ece80eabe1982fbfda0.gif)
    
    • 1
    • 2
    • 3
    • 4
  • 相关阅读:
    W5500+树莓派RP2040入门教程之MQTT篇(十二)
    【一起学前端:HTML5+CSS3】02-转义字符和语义化标签
    创新与重塑,佛塑科技打造集团型 CRM 建设标杆
    前端html实现带行号的文本编辑器
    Git小乌龟不弹add push commit的方法
    两日总结十
    spring复习:(62)自定义PropertySourcesPlaceHolderConfigurer
    Stateful DHCPv6
    【知识网络分析】作者合作网络(Co-authorship)
    springcloud3 分布式事务-seata的四种模式总结以及异地容灾
  • 原文地址:https://blog.csdn.net/qq_24472227/article/details/132740512