QT实现贪吃蛇游戏代码详解

 更新时间:2021年11月18日 09:29:15   作者:五里之南  
本文主要为大家详细介绍了在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;
 
}

五、结束

实现的效果:


总结:

只是简单的使用了paintevent进行绘图,基本都是简单的对Qt的一些常用类的使用,对面向对象的编程应用的不是很好,更偏向于面向过程,所以完全可以改成C语言在Linux下实现,思路都是相同的。

到此这篇关于QT实现贪吃蛇游戏代码详解的文章就介绍到这了,更多相关QT内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • VC外部符号错误_main,_WinMain@16,__beginthreadex解决方法

    VC外部符号错误_main,_WinMain@16,__beginthreadex解决方法

    这篇文章主要介绍了VC外部符号错误_main,_WinMain@16,__beginthreadex解决方法,实例分析了比较典型的错误及对应的解决方法,需要的朋友可以参考下
    2015-05-05
  • C++调用libcurl开源库实现邮件的发送功能流程详解

    C++调用libcurl开源库实现邮件的发送功能流程详解

    libcurl是一个免费开源的网络传输库,支持ftp、ftps、tftp,http、https、telnet、ldap、pop3、smtp等多种协议,接下来让我们一起来了解吧
    2021-11-11
  • C++ 内联函数inline案例详解

    C++ 内联函数inline案例详解

    这篇文章主要介绍了C++ 内联函数inline案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-09-09
  • C语言实现输入一个字符串后打印出该字符串中字符的所有排列

    C语言实现输入一个字符串后打印出该字符串中字符的所有排列

    这篇文章主要介绍了C语言实现输入一个字符串后打印出该字符串中字符的所有排列的方法,是数学中非常实用的排列算法,需要的朋友可以参考下
    2014-09-09
  • c语言详解动态内存分配及常见错误的解决

    c语言详解动态内存分配及常见错误的解决

    给数组分配多大的内存空间?你是否和初学C时的我一样,有过这样的疑问。这一期就来聊一聊动态内存的分配,读完这篇文章,你可能对内存的分配有一个更好的理解
    2022-04-04
  • 带你了解如何用C++合并两个有序链表

    带你了解如何用C++合并两个有序链表

    这篇文章主要介绍了c++ 如何合并两个有序链表,小编感觉这篇文章还不错,希望能帮助大家更好的理解和学习C++,感兴趣的朋友可以了解下
    2021-08-08
  • OpenCV 2.4.3 C++ 平滑处理分析

    OpenCV 2.4.3 C++ 平滑处理分析

    平滑也称模糊, 是一项简单且使用频率很高的图像处理方法,本文将详细介绍OpenCV 2.4+ C++ 平滑处理,需要了解更多的朋友可以详细参考下
    2012-11-11
  • 浅谈C++ Socket编程

    浅谈C++ Socket编程

    本文给大家简单介绍了C++中的Socket编程的种类以及sockets编程的8个步奏,简单生动,有需要的小伙伴可以参考下
    2017-07-07
  • 详解C语言实现猜数字游戏

    详解C语言实现猜数字游戏

    这篇文章主要为大家介绍了C语言实现猜数字游戏,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助<BR>
    2022-01-01
  • C/C++ 宏详细解析

    C/C++ 宏详细解析

    关于宏的一些语法问题,可以在google上找到。相信我,你对于宏的了解绝对没你想象的那么多。如果你还不知道#和##,也不知道prescan,那么你肯定对宏的了解不够
    2013-09-09

最新评论