Qt small project Snake Solid Line, mainly masters timers, signals and slots, key events, drawing events, coordinate operations, random number generation, etc.

Qt small project Snake Solid Line, mainly masters timers, signals and slots, key events, drawing events, coordinate operations, random number generation, etc.

Qt Snake Demo

Insert image description here
Insert image description here
Insert image description here

QWidget drawing interface

Insert image description here
Insert image description here

Project source files are clearly commented

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QtDebug>


#include <QKeyEvent>
#include <QTimer>
#include <QRectF>
#include <QPointF>

#include <QIcon>
#include <QPainter>

QT_BEGIN_NAMESPACE
namespace Ui {
    
     class Widget; }
QT_END_NAMESPACE

typedef enum direct {
    
    
    dir_UP,
    dir_DOWN,
    dir_LEFT,
    dir_RIGHT
}dir_t;


class Widget : public QWidget
{
    
    
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    void topAddRect();
    void deleteLast();
    void downAddRect();
    void leftAddRect();
    void rightAddRect();

    void addFood();

    bool  checkHit();

protected:
    // 按键按压处理
    void keyPressEvent(QKeyEvent *event);
    void paintEvent(QPaintEvent *event);

private Q_SLOTS:
    void my_timeout();

private:
    Ui::Widget *ui;

    int moveFlag = dir_t::dir_UP;
    bool gameStart = false;

    QTimer *timer;
    const int startTime = 100;

    // 贪吃蛇
    QList<QRectF>snakeList;

    // 贪吃蛇小方块
    const int  nodeWidth = 20;
    const  int  nodeHeight = 20;

    // 食物
    QRectF food;

};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"

// 三个方块代码蛇,最上面的第一个和最后面的一个通过按键进行交替删除 即snake[0]永远表示头


Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    
    
    ui->setupUi(this);
    this->setWindowTitle("贪吃蛇疯子");
    this->setWindowIcon(QIcon(":/icons/title.jpg"));

    qDebug()<<"x = "<<this->x()<<" y = "<<this->y()<<" height = "<<this->height()<<" width = "<<this->width();

    timer = new QTimer();
    connect(timer, &QTimer::timeout, this , &Widget::my_timeout);

    // 初始化蛇身子 3个方块
    QRectF rect(this->width()/2,this->height()/2,nodeWidth,nodeHeight);
    snakeList.append(rect);
    topAddRect();
    topAddRect();

   // 添加食物
   addFood();
}

Widget::~Widget()
{
    
    
    delete ui;
}

// 增加一个方块 左上和右下确认一个方块坐标系
void Widget::topAddRect()
{
    
    
    QPointF leftTop;                // 左上角坐标
    QPointF rightBottom;       // 右上角坐标

    if (snakeList[0].y()  <=  0) {
    
    
        // 当蛇移动到窗口顶部:确认新坐标 y = 窗口高度 - 蛇方块高度
        leftTop = QPointF(snakeList[0].x(), this->height() - nodeHeight);
        rightBottom  = QPointF(snakeList[0].x() + nodeWidth , this->height());
    }
    else {
    
    
        // 向上移动: y坐标必然减少 减少的右下角坐标为之前的下一个方块的右上角坐标
        leftTop = QPointF(snakeList[0].x(), snakeList[0].y() - nodeHeight);
        rightBottom = snakeList[0].topRight();
    }

    // 插入矩形小方块1个,由于采用的是List链表,这是典型的前插,追加
    snakeList.insert(0,QRectF(leftTop,rightBottom));
}

void Widget::downAddRect()
{
    
    
    QPointF leftTop;                // 左上角坐标
    QPointF rightBottom;       // 右上角坐标

    if (snakeList[0].y() > this->height() - nodeHeight) {
    
    
        // 当蛇移动到窗口底部:确认新坐标 y = 0
        leftTop = QPointF(snakeList[0].x(), 0);
        rightBottom  = QPointF(snakeList[0].x() + nodeWidth, 0 + nodeHeight);
    }
    else {
    
    
        // 向下移动: y坐标必然增加
        leftTop = QPointF(snakeList[0].x(), snakeList[0].y() + nodeHeight);
        rightBottom = snakeList[0].bottomRight() + QPointF(0,nodeHeight);
    }

    // 插入矩形小方块1个
    snakeList.insert(0,QRectF(leftTop,rightBottom));
}

void Widget::leftAddRect()
{
    
    
    QPointF leftTop;                // 左上角坐标
    QPointF rightBottom;       // 右上角坐标

    if (snakeList[0].x() <= 0) {
    
    
        // 当蛇移动到窗口最左部:确认新坐标 x = 窗口宽度 - 小方块宽度
        leftTop = QPointF(this->width() - nodeWidth, snakeList[0].y());
    }
    else {
    
    
        // 向左移动:x坐标必然减少
        leftTop = QPointF(snakeList[0].x() - nodeWidth, snakeList[0].y());
    }

    // 右下角坐标 = 之前一个的左上角坐标x,y + 小方块的宽高
    rightBottom  = leftTop + QPointF(nodeWidth, nodeHeight);

    // 插入矩形小方块1个
    snakeList.insert(0,QRectF(leftTop,rightBottom));
}

void Widget::rightAddRect()
{
    
    
    QPointF leftTop;                // 左上角坐标
    QPointF rightBottom;       // 右上角坐标

    if (snakeList[0].x() + nodeWidth > this->width()) {
    
    
        // 当蛇移动到窗口最右部:确认新坐标 x  = 0
        leftTop = QPointF(0, snakeList[0].y());
    }
    else {
    
    
        // 向右移动:x坐标必然增加
        leftTop = QPointF(snakeList[0].x() + nodeWidth, snakeList[0].y());
    }

    // 右下角坐标 = 之前一个的左上角坐标x,y + 小方块的宽高
    rightBottom  = leftTop + QPointF(nodeWidth, nodeHeight);

    // 插入矩形小方块1个
    snakeList.insert(0,QRectF(leftTop,rightBottom));
}

// 删除蛇身最后一个
void Widget::deleteLast()
{
    
    
    snakeList.removeLast();
}

// 食物是随机出现的
void Widget::addFood()
{
    
    
    int rectX = (qrand() % (this->width() / 20)) * 20;
    int rectY = (qrand() % (this->height() / 20)) * 20;

    // 控制小球出现的范围
    if (rectX >= 0 && rectY>=0) {
    
    
         food = QRectF(rectX, rectY, nodeWidth, nodeHeight);
         qDebug()<<"food = "<<food;
    }
}

// 蛇头和蛇身碰撞检查,其实就是蛇头和蛇尾其中一个方块重合
bool Widget::checkHit()
{
    
    
    // 整个蛇的长度都遍历一遍
    for (int i =0 ; i < snakeList.length(); i++) {
    
    
        // 从蛇头后的第一个开始检查 只要有
        for (int j=  i+ 1; j < snakeList.length();j++) {
    
    
             // rect0和rectx相等,表示它们的坐标、宽度和高度都一致
            if (snakeList[0] == snakeList[j]) {
    
    
                return true;
            }
        }
    }

    return false;
}

void Widget::keyPressEvent(QKeyEvent *event)
{
    
    
    switch (event->key()) {
    
    
    case Qt::Key::Key_Up:
        if (moveFlag != dir_DOWN) {
    
    
            moveFlag = dir_UP;
        }
        break;
    case Qt::Key::Key_Down:
         if (moveFlag != dir_UP) {
    
    
            moveFlag = dir_DOWN ;
         }
        break;
    case Qt::Key::Key_Left:
        if (moveFlag != dir_RIGHT) {
    
    
            moveFlag = dir_LEFT;
        }
        break;
    case Qt::Key::Key_Right:
        if (moveFlag != dir_LEFT) {
    
    
            moveFlag = dir_RIGHT;
        }
        break;
    case Qt::Key_Space:
        if (gameStart == false) {
    
    
            gameStart = true;
            timer->start(startTime); // 100ms
        }
        else {
    
    
            gameStart = false;
            timer->stop();
        }
        break;
    default:
        break;
    }
}

void Widget::paintEvent(QPaintEvent *event)
{
    
    
    QPainter painter(this);
    QPen pen;
    QBrush brush;

    QPixmap pix;
    // 绘制图片背景
    pix.load(":/icons/bg_snake.png");
    painter.drawPixmap(0,0,this->width(),this->height(),pix);

    // 绘制蛇
    pen.setColor(Qt::color0);
    brush.setColor(Qt::darkGreen);          // 绿色
    brush.setStyle(Qt::SolidPattern);       // 实线图案
    painter.setPen(pen);
    painter.setBrush(brush);

    for (int i = 0; i < snakeList.length(); i++) {
    
    
        painter.drawRect(snakeList[i]);
    }
    // 分数
    ui->label_score->setText(QString::number(snakeList.length() -3));

    // 绘制食物
    painter.drawEllipse(food);

    // 蛇头碰到蛇身结束游戏
    if (checkHit()) {
    
    
       QFont font("方正舒体",30,QFont::ExtraLight,false);
       painter.setFont(font);
       painter.drawText((this->width() - 200)/2,this->height()/2,QString("游戏结束"));

        timer->stop();
    }


    QWidget::paintEvent(event);

}

// 定时器槽函数
void Widget::my_timeout()
{
    
    
    //int count = 1;  // 采用这种方式也可以加长蛇身,不过我还是喜欢我的烂方法

    // 判断蛇是否吃到食物 是否重合[交叉;相交;贯穿;横穿;横断]  蛇变长
    if (snakeList[0].intersects(food)) {
    
    
        qDebug()<<"吃到食物 snakeList[0] = "<<snakeList[0]<<" food = "<<food;
        //count ++ ;      // 例如 2
        switch (moveFlag) {
    
    
        case dir_UP:
            this->topAddRect();         // +1
            break;
        case dir_DOWN:
            this->downAddRect();     // +1
            break;
        case dir_LEFT:
            this->leftAddRect();        // +1
            break;
        case dir_RIGHT:
            this->rightAddRect();     // +1
            break;
        default:
            break;
        }
        addFood();    // 食物位置变化
        return;
    }

    // 加长蛇身  每次在最前面增加一个
   // while (count--) {
    
    
        switch (moveFlag) {
    
    
        case dir_UP:
            this->topAddRect();         // +1
            break;
        case dir_DOWN:
            this->downAddRect();     // +1
            break;
        case dir_LEFT:
            this->leftAddRect();        // +1
            break;
        case dir_RIGHT:
            this->rightAddRect();     // +1
            break;
        default:
            break;
        }
    //}

     // 为了动态显示每次最前面插入一个,最后面就减少一个
    deleteLast();       // 删除蛇尾  -1
    this->update(); // 刷新绘制函数
}


expand

QTimer

QTimer is a class used for timer operations in Qt. It provides some commonly used functions to control and manage the operation of timers. The following is an introduction to some commonly used QTimer functions:

  1. start(int msec): Start the timer and trigger the timeout() signal of the timer at the specified interval of milliseconds.
  2. stop(): Stop the timer and no longer trigger the timeout() signal.
  3. setInterval(int msec): Set the timer interval in milliseconds.
  4. interval(): Get the current timer interval.
  5. isActive(): Determine whether the timer is active, that is, whether it is running.
  6. setSingleShot(bool singleShot): Set the running mode of the timer. If set to true, the timer will only trigger once; if set to false (default value), the timer will always trigger.
  7. singleShot(int msec, const QObject* receiver, const char* member): Create a single-trigger timer, specify the trigger time, the object receiving the signal and the corresponding slot function.
  8. remainingTime(): Get the remaining trigger time of the timer, in milliseconds.

These functions provide basic timer operation functions and can be used in conjunction with the timer's signal timeout() and connection (Qt's signal and slot mechanism) to achieve the required timing operations.

QKeyEvent

QKeyEvent is a class in Qt used to handle keyboard events. It provides some commonly used functions to obtain and process information related to keyboard events. The following is an introduction to some commonly used QKeyEvent functions:

  1. key(): Get the Qt keyboard code of the key that triggers the keyboard event, and return a Qt::Key enumeration value.
  2. text(): Get the text corresponding to the key that triggered the keyboard event and return a QString.
  3. modifiers(): Get the modifier key status when the keyboard event is triggered, and return a Qt::KeyboardModifiers enumeration value, which can be used to check the status of modifier keys such as Shift, Ctrl, Alt, etc.
  4. isAutoRepeat(): Determine whether the key that triggers the keyboard event is an automatically repeated press event.
  5. count(): Get the number of times the automatic repeat key is triggered continuously.
  6. nativeVirtualKey(): Get the virtual key code of the underlying platform and return an int value.
  7. nativeModifiers(): Get the modifier key status of the underlying platform and return an int value.

These functions can help you obtain information related to keyboard events, such as getting which key was pressed, whether modifier keys were pressed at the same time, and the number of times the event was automatically repeated. You can use these functions to handle keyboard events and perform corresponding actions as needed.

QRectF

QRectF is a class in Qt used to represent a rectangular area with floating point precision. It provides some commonly used functions to operate and manage rectangular areas. The following is an introduction to some commonly used QRectF functions:

  1. QRectF(): Default constructor, creates an invalid rectangular area.
  2. QRectF(qreal x, qreal y, qreal width, qreal height): Constructor that creates a rectangular area defined with given coordinates, width, and height.
  3. setRect(qreal x, qreal y, qreal width, qreal height): Set the position and size of the rectangular area.
  4. setCoords(qreal x1, qreal y1, qreal x2, qreal y2): Set the coordinates of the upper left corner and lower right corner of the rectangular area.
  5. x(), y(), width(), height(): Get the x and y coordinates of the upper left corner of the rectangular area, as well as the width and height.
  6. left(), top(), right(), bottom(): Get the coordinates of the left, upper, right and lower boundaries of the rectangular area.
  7. setX(qreal x), setY(qreal y), setWidth(qreal width), setHeight(qreal height): Set the x and y coordinates of the upper left corner of the rectangular area, as well as the width and height.
  8. setLeft(qreal left), setTop(qreal top), setRight(qreal right), setBottom(qreal bottom): Set the coordinates of the left, upper, right and lower boundaries of the rectangular area.
  9. moveTo(qreal x, qreal y): Moves the position of the rectangular area and sets its upper left corner to the given coordinates.
  10. translated(qreal dx, qreal dy): Translate the rectangular area by the given distance in the x and y directions.
  11. contains(const QPointF &point): Determine whether the rectangular area contains the given point.
  12. isEmpty(): Determine whether the rectangular area is empty, that is, whether the width or height is 0.
  13. isNull(): Determine whether the rectangular area is empty, that is, whether the width and height are 0.

QPointF

QPointF is a class in Qt used to represent two-dimensional points with floating point precision. It provides some commonly used functions to operate and manage the coordinates of points. The following is an introduction to some commonly used QPointF functions:

  1. QPointF(): Default constructor, creates a point with zero-valued coordinates.
  2. QPointF(qreal x, qreal y): Constructor that creates a point with given coordinates.
  3. setX(qreal x), setY(qreal y): Set the x and y coordinates of the point.
  4. x(), y(): Get the x and y coordinates of the point.
  5. isNull(): Determine whether the point is empty, that is, whether the coordinates are zero.
  6. manhattanLength(): Calculate the Manhattan distance (sum of absolute values) from a point to the coordinate origin.
  7. distanceToLine(const QLineF &line): Calculates the distance from a point to a given straight line.
  8. distanceToPoint(const QPointF &point): Calculates the distance from a point to a given point.
  9. operator==(const QPointF &p1, const QPointF &p2): Determine whether two points are equal.
  10. operator!=(const QPointF &p1, const QPointF &p2): Determine whether two points are not equal.
  11. isNull(const QPointF &point): Determine whether the given point is empty, that is, whether the coordinates are zero.

These functions provide basic operations on points, including setting coordinates, obtaining coordinates, determining whether a point is empty, calculating distances from other points or straight lines, etc. You can use these functions to create, modify, and calculate the coordinates of points to suit your needs.

QPainter

QPainter is a class provided by Qt for drawing. It encapsulates the function of drawing graphics, images and text. The following is an introduction to some commonly used QPainter functions:

  1. begin(QPaintDevice *device): Start drawing on a given drawing device. The device can be QWidget, QImage, etc.
  2. end(): End the drawing operation.
  3. setPen(const QPen &pen): Set the drawing brush, used to define the style, color and other attributes of the line.
  4. setBrush(const QBrush &brush): Set the drawing brush to fill in the color, gradient and other attributes of the closed shape.
  5. setRenderHint(RenderHint hint, bool on = true): Turn on or off drawing rendering hints, such as anti-aliasing, text anti-aliasing, etc.
  6. drawLine(const QLine &line): Draw a straight line.
  7. drawRect(const QRect &rect): Draw a rectangle.
  8. drawEllipse(const QRect &rect): Draw an ellipse.
  9. drawText(const QPointF &pos, const QString &text): Draws text at a given point.
  10. drawPixmap(const QRectF &targetRect, const QPixmap &pixmap): Draws a pixel map in a given rectangular area.
  11. save(), restore(): Save and restore the drawing state, used to achieve switching of drawing states, overlay effects, etc.
  12. resetTransform(): Reset the coordinate transformation matrix.
  13. translate(qreal dx, qreal dy): The origin of the translation brush.
  14. scale(qreal sx, qreal sy): Scale the brush to adjust the drawing proportionally.
  15. rotate(qreal angle): Rotate the brush around the origin.

These functions provide the ability to draw basic graphics, text, and images. By setting attributes such as brushes, brushes, and rendering tips, different styles of drawing effects can be achieved. At the same time, you can also use transformation functions such as translation, scaling, and rotation to change the drawing position and direction of the brush. Using these functions, you can implement various drawing needs and create rich and diverse user interfaces.

QIcon

QIcon is a class provided by Qt for managing icons. It can load, display and operate icons. The following is an introduction to some commonly used QIcon functions:

  1. QIcon(): Default constructor, creates an empty icon.
  2. QIcon(const QString &filename): Constructor, loads the icon according to the given file name.
  3. QIcon(const QPixmap &pixmap): Constructor, creates an icon based on the given pixmap.
  4. QIcon(const QIcon &other): Copy constructor, creates an identical copy of the given icon.
  5. addFile(const QString &filename, const QSize &size = QSize(), QIcon::Mode mode = QIcon::Normal, QIcon::State state = QIcon::Off): Add an image file to the icon, and you can specify the size, mode and status of the image.
  6. isNull(): Determine whether the icon is empty, that is, no image is loaded.
  7. pixmap(const QSize &size, QIcon::Mode mode = QIcon::Normal, QIcon::State state = QIcon::Off) const: Get the pixel image of the icon, and you can specify the size, mode and status of the image.
  8. paint(QPainter *painter, const QRect &rect, Qt::Alignment alignment = Qt::AlignCenter, QIcon::Mode mode = QIcon::Normal, QIcon::State state = QIcon::Off) const: Draws an icon within a given rectangular area. Alignment, mode and state can be specified.
  9. operator=(const QIcon &other): Assignment operator, copies the contents of the given icon to the current icon.
  10. operator==, operator!=: Used to compare whether two icons are equal or unequal.

These functions provide the functions of loading, displaying and operating icons. You can load image files as needed, set the size, mode and status of the icon, draw the icon to the specified area, and perform icon comparison and assignment operations. The QIcon class is widely used in interface development in Qt, which makes the management and use of icons simple and flexible.

Guess you like

Origin blog.csdn.net/m0_45463480/article/details/132134099