基于C++的QT实现贪吃蛇小游戏

news2024/12/24 2:33:11

文章目录:

一:效果演示

二:实现思路

三:代码实现 

widget.h

widget.cpp

main.cpp


一:效果演示

 效果图◕‿◕✌✌✌ 

代码下载

二:实现思路

 通过按键控制蛇的移动,每吃一个商品蛇身就会加长,如果蛇身头尾相碰就结束游戏

声明渲染绘图:画笔画刷进行相关的渲染背景蛇和奖品	


按键处理机制:方便后面的键盘操作
	定时器:到时就会触发
	按下空格:代表开始
	上下左右键控制蛇的移动方向:DIR_DOWN DIR_UP DIR_LEFT DIR_RIGHT

蛇:
	蛇的表示:矩形的两点确定小方块,3个小方块为初始蛇身
	判断蛇身蛇头:如果蛇头蛇尾接触就结束游戏
	蛇身变动:相交就吃掉奖品,吃一个加一个小方块
	

奖品
	奖品的表示:小红点
	奖品的添加:蛇吃完一个奖品就马上随机添加一个奖品

蛇吃奖品:
	吃一个奖品会加一个方块:上面、下面、左面、右面

三:代码实现 

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
//按键
#include <QKeyEvent>
//定时器
#include <QTimer>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE



//定义方向
enum Dirct{DIR_LEFT,DIR_RIGHT,DIR_DOWN,DIR_UP};


class Widget : public QWidget
{
    Q_OBJECT

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

protected:
    //声明渲染绘图
    void paintEvent(QPaintEvent *event);

    //声明按键处理
    void keyPressEvent(QKeyEvent *event);

    //声明上面加一个函数
    void addTop();
    //声明下面加一个函数
    void addDown();
    //声明左面加一个函数
    void addLeft();
    //声明右面加一个函数
    void addRight();

    //声明减去一个模块
    void deleteLast();

    //声明添加奖品函数
    void addNewReword();

    //声明判断蛇头蛇身
    bool checkContact();

private:
    Ui::Widget *ui;
    //初始化定义方向
    int moveFlag = DIR_UP;
    //定义启动的开始
    bool gameStart = false;

    //定义定时器
    QTimer *timer;
    int time = 100;//超时事件间隔(毫秒)

    //蛇的表示  矩形两点确定(容器)
    QList <QRectF> snake;

    //小方块表示
    int nodeWidth = 20;
    int nodeHeight = 20;

    //奖品的表示
    QRectF rewardNode;

protected slots:
    //定义超时函数
    void timeout();
};


#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <qmediaplayer.h>

//画家
#include <QPainter>
//文字
#include <QRandomGenerator>
//背景音乐
#include <QtMultimedia/QtMultimedia>
#include <QtMultimediaWidgets/QVideoWidget>
#include <QApplication>
#include <QMediaPlayer>
#include <QUrl>
#include <QFileDialog>


Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //定义窗口大小
        //resize(800,600);
        this->setFixedSize(800,600);

    QMediaPlayer *player = new QMediaPlayer;
    player->setSource(QUrl::fromLocalFile("F:/QT/Snake/images/mu.mp3"));
    player->play();

    //实现定时器 可以让蛇动起来
        //创建定时器
        timer = new QTimer();
        //信号槽   timeout超时
        connect(timer,SIGNAL(timeout()),this,SLOT(timeout()));

    //初始化蛇身
        QRectF rect(400,300,nodeWidth,nodeHeight);
        //小方块加到蛇身上去
        snake.append(rect);
        //再加两端
        addTop();
        addTop();

    //初始化奖品
        addNewReword();


    //背景音乐
//        //创建一个显示视频的控件
//                QVideoWidget* videowin = new QVideoWidget(this);
//                videowin->resize(400,300);
//                //添加一个播放器
//                QMediaPlayer *player = new QMediaPlayer(this);
//                player->setVideoOutput(videowin);
//                //音乐
//                player->setMedia(QMediaContent(QUrl::fromLocalFile("F:/QT/Snake/images/game.mp3")));
//                //player->setVolume(50);//音量
//                //开始播放
//                player->play();






}

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

//实现按键函数    控制方向
void Widget::keyPressEvent(QKeyEvent *event){
    switch (event->key()) {
    case Qt::Key_Up:
        if(moveFlag != DIR_DOWN){moveFlag = DIR_UP;}
        break;
    case Qt::Key_Down:
        if(moveFlag != DIR_UP){moveFlag = DIR_DOWN;}
        break;
    case Qt::Key_Right:
        if(moveFlag != DIR_LEFT){moveFlag = DIR_RIGHT;}
        break;
    case Qt::Key_Left:
        if(moveFlag != DIR_RIGHT){moveFlag = DIR_LEFT;}
        break;
    case Qt::Key_Space:
        if(gameStart == false){
            gameStart = true;
            //启动定时器
            timer->start(time);
        }
        else{
            gameStart = false;
            //停止定时器
            timer->stop();
        }
        break;
    default:
        break;
    }
}


//实现超时函数
void Widget::timeout(){//实现逻辑要么都上移,要么底部加一个,顶部取消一个
    //判断有没有重合
    int count = 1;
    if(snake[0].intersects(rewardNode)){
        //相交就吃掉奖品
        count++;
        //吃掉添加新的奖品
        addNewReword();
    }

    while (count--) {
        //蛇的移动
        switch (moveFlag) {
        case DIR_UP:
            addTop();
            break;
        case DIR_DOWN:
            addDown();
            break;
        case DIR_LEFT:
            addLeft();
            break;
        case DIR_RIGHT:
            addRight();
            break;
        default:
            break;
        }
    }

    //删除一个
    deleteLast();
    //刷新一下
    update();

}

//实现上面加一个函数
void Widget::addTop(){
    QPointF leftTop;
    QPointF rightBotom;

    //超出边界(顶端) 加到最下面
    if(snake[0].y()-nodeHeight < 0){
        //this->height窗口
        leftTop = QPoint(snake[0].x(),this->height()-nodeHeight);
        rightBotom = QPointF(snake[0].x()+nodeWidth,this->height());
    }else{
    //没有超出的情况
        //在蛇的上面(蛇和矩形)
        //左上角坐标     nodeHeight小方块矩形
        leftTop = QPointF(snake[0].x(),snake[0].y()-nodeHeight);
        //右下角坐标
        rightBotom = snake[0].topRight();
    }

    //加一个小方块
    snake.insert(0,QRectF(leftTop,rightBotom));
}


//实现下面加一个函数
void Widget::addDown(){
    QPointF leftTop;
    QPointF rightBotom;

    //超出边界(顶端) 加到最下面
    if(snake[0].y()+nodeHeight*2 > this->height()){
        leftTop = QPointF(snake[0].x(),0);
        rightBotom = QPointF(snake[0].x()+nodeWidth,nodeHeight);
    }else{
        //没有超出的情况
        //在蛇的上面(蛇和矩形)
        //左上角坐标     nodeHeight小方块矩形
        leftTop = snake[0].bottomLeft();
        //右下角坐标
        rightBotom = snake[0].bottomRight()+QPointF(0,nodeHeight);
    }

    //加一个小方块
    snake.insert(0,QRectF(leftTop,rightBotom));
}


//实现左面加一个函数
void Widget::addLeft(){
    QPointF leftTop;
    QPointF rightBotom;

    //超出边界(顶端) 加到最下面
    if(snake[0].x()-nodeWidth < 0){
        leftTop = QPointF(this->width()-nodeWidth,snake[0].y());
    }else{
        //没有超出的情况
        //在蛇的上面(蛇和矩形)
        //左上角坐标     nodeHeight小方块矩形
        leftTop = snake[0].topLeft()-QPointF(nodeWidth,0);
    }

    rightBotom = leftTop+QPointF(nodeWidth,nodeHeight);
    //右下角坐标
    //加一个小方块
    snake.insert(0,QRectF(leftTop,rightBotom));
}


//实现右面加一个函数
void Widget::addRight(){
    QPointF leftTop;
    QPointF rightBotom;

    //超出边界(顶端) 加到最下面
    if(snake[0].x()-nodeWidth*2 > this->width()){
        leftTop = QPointF(0,snake[0].y());
    }else{
        //没有超出的情况
        //在蛇的上面(蛇和矩形)
        //左上角坐标     nodeHeight小方块矩形
        leftTop = snake[0].topRight();
    }

    rightBotom = leftTop+QPointF(nodeWidth,nodeHeight);
    //右下角坐标
    //加一个小方块
    snake.insert(0,QRectF(leftTop,rightBotom));
}





//实现绘图
void Widget::paintEvent(QPaintEvent *event){
    //画家
    QPainter painter(this);
    //画笔
    QPen pen;
    //画刷
    QBrush brush;

    //背景图片
    QPixmap pix;
    pix.load("F:/QT/Snake/images/bk.png");
    //    QPixmap pixmap(":/images/bk.png");
    painter.drawPixmap(0,0,800,600,pix);

    //画蛇
        //画笔
        pen.setColor(Qt::black);
        //画刷
        brush.setColor(Qt::darkMagenta);
        brush.setStyle(Qt::SolidPattern);

        //画家使用画笔和画刷
        painter.setPen(pen);
        painter.setBrush(brush);

        //画蛇的头尾
        for(int i=0;i<snake.length();i++){
            painter.drawRect(snake[i]);
        }

    //画奖品
        //画笔
        pen.setColor(Qt::red);
        //画刷
        brush.setColor(Qt::red);
        brush.setStyle(Qt::SolidPattern);

        //画家使用画笔和画刷
        painter.setPen(pen);
        painter.setBrush(brush);
        //painter.drawRect(rewardNode);//奖品
        painter.drawEllipse(rewardNode);

    //判断蛇头是否碰到蛇身
        if(checkContact()){
            QFont font("方块输出",30,QFont::ExtraLight,false);
            painter.setFont(font);
            painter.drawText(
                    (this->width()-300)/2,
                    (this->height()-30)/2,
                    QString("完成")
                );
            timer->stop();
        }

    //调用一下父类
    QWidget::paintEvent(event);
}


//实现减去一个方块
void Widget::deleteLast(){
    snake.removeLast();
}


//实现添加奖品函数
void Widget::addNewReword(){
    //奖品
    int width = this->width();
    int a = QRandomGenerator::global()->bounded(width/20*20);
    int height = this->height();
    int b = QRandomGenerator::global()->bounded(height/20*20);
    rewardNode = QRectF(
            //qrand()%(this->width()/20)*20,
            //qrand()%(this->height()/20)*20,
            //QT6用上面方法会报错:'qrand' was not declared in this scope; did you mean 'srand'?
            a,
            b,
            nodeWidth,
            nodeHeight
        );
}


//实现判断蛇头是否碰到蛇身函数
bool Widget::checkContact(){
    for(int i = 1; i < snake.length(); i++)
        for (int j = i+1; j < snake.length(); j++) {
                if(snake[i] == snake[j]){
                    return true;
                }
        }
    return false;
}

main.cpp

#include "widget.h"

#include <QApplication>
#include <QLocale>
#include <QTranslator>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QTranslator translator;
    const QStringList uiLanguages = QLocale::system().uiLanguages();
    for (const QString &locale : uiLanguages) {
        const QString baseName = "Snake_" + QLocale(locale).name();
        if (translator.load(":/i18n/" + baseName)) {
            a.installTranslator(&translator);
            break;
        }
    }
    Widget w;
    w.show();
    return a.exec();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/911653.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

16.5.6 【Linux】一个网络服务案例及登录文件协助

setroubleshoot --> 错误讯息写入 /var/log/messages 几乎所有 SELinux 相关的程序都会以 se 为开头&#xff0c;这个服务也是以 se 为开头。troubleshoot是错误克服&#xff0c;因此setroubleshoot要启动。这个服务会将关于 SELinux 的错误讯息与克服方法记录到 /var/log/…

优化指南:带宽限制的可行策略

大家好&#xff01;作为一名专业的爬虫程序员&#xff0c;我们经常面临的一个挑战就是带宽限制。尤其是在需要快速采集大量数据时&#xff0c;带宽限制成为了我们提升爬虫速度的一大阻碍。今天&#xff0c;我将和大家分享一些解决带宽限制的可行策略&#xff0c;希望能帮助大家…

问道管理:沪指失守3100点 机构判断“市场底”渐行渐近

8月21日&#xff0c;沪深两市股指盘中全线走低&#xff0c;三大股指收盘均跌超1%&#xff0c;其间沪指收盘指数今年以来初次失守3100点&#xff0c;创业板指更是3年多来初次跌破2100点。截至收盘&#xff0c;沪指跌1.24%报3092.98点&#xff0c;深证成指跌1.32%报10320.39点&am…

ResizeObserver监听元素大小的变化

window.resize不适用于dom的监听。 ResizeObserver ResizeObserver 接口监视 Element 内容盒或边框盒或者 SVGElement 边界尺寸的变化。 方法 ResizeObserver.disconnect() 取消特定观察者目标上所有对 Element 的监听。 ResizeObserver.observe() 开始对指定 Element 的监…

NLP预训练模型超大规模探索

总共从四方面来进行比较。 第一个方面&#xff0c;高层次方法&#xff08;自监督的预训练方法&#xff09;对比&#xff0c;总共三种方式。 语言模型式&#xff0c;就是 GPT-2 那种方式&#xff0c;从左到右预测&#xff1b;BERT-style 式&#xff0c;就是像 BERT 一样将一部…

通过几段代码,详解Python单线程、多线程、多进程

在使用爬虫爬取数据的时候&#xff0c;当需要爬取的数据量比较大&#xff0c;且急需很快获取到数据的时候&#xff0c;可以考虑将单线程的爬虫写成多线程的爬虫。下面来学习一些它的基础知识和代码编写方法。 一、进程和线程 进程可以理解为是正在运行的程序的实例。进程是拥…

卷积神经网络实现天气图像分类 - P3

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f366; 参考文章&#xff1a;Pytorch实战 | 第P3周&#xff1a;彩色图片识别&#xff1a;天气识别&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制&#x1f680; 文章来源&#xff…

问道管理:中国十大科技板块?

跟着科技的开展&#xff0c;各种高科技工业在我国迅猛开展&#xff0c;其中十大板块就是一个比较典型的代表。这十大科技板块涵盖了从电子信息、生命健康到新材料等多个范畴&#xff0c;让我们一起来了解一下这十大板块的开展现状。 一、电子信息 作为国家重点支持开展的工业之…

剑指offer(C++)-JZ64:求1+2+3+...+n(算法-位运算)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 题目描述&#xff1a; 求123...n&#xff0c;要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句&…

如何使用数学将 NumPy 函数的性能提高 50%

一、说明 2D 傅里叶变换是本世纪最重要的计算机科学算法之一。它已在我们的日常生活中得到应用&#xff0c;从Instagram过滤器到MP3文件的处理。 普通用户最常用的实现&#xff0c;有时甚至是在不知不觉中&#xff0c;是 NumPy 的改编。然而&#xff0c;尽管它很受欢迎&#xf…

CDH集群离线配置python3环境,并安装pyhive、impyla、pyspark

背景&#xff1a; 项目需要对数仓千万级数据进行分析、算法建模。因数据安全&#xff0c;数据无法大批量导出&#xff0c;需在集群内进行分析建模&#xff0c;但CDH集群未安装python3 环境&#xff0c;需在无网情况下离线配置python3环境及一系列第三方库。 采取策略&#xf…

python分析实战(4)--获取某音热榜

1. 分析需求 打开某音热搜&#xff0c;选择需要获取的热榜如图 查找包含热搜内容的接口返回如图 将url地址保存 2. 开发 定义请求头 headers {Cookie: 自己的cookie,Accept: application/json, text/plain, */*,Accept-Encoding: gzip, deflate,Host: www.douyin.com,…

vue3+element下拉多选框组件

<!-- 下拉多选 --> <template><div class"select-checked"><el-select v-model"selected" :class"{ all: optionsAll, hidden: selectedOptions.data.length < 2 }" multipleplaceholder"请选择" :popper-app…

C++信息学奥赛1129:统计数字字符个数

这段代码的功能是计算一个输入字符串中的数字字符个数。 解析注释后的代码如下&#xff1a; #include<bits/stdc.h> using namespace std; int main() {string arr; // 定义字符串变量arr&#xff0c;用来存储输入的字符串getline(cin, arr); // 通过getline函数输入完…

企业文件透明加密软件——「天锐绿盾」数据防泄密管理软件系统

PC访问地址&#xff1a; 首页 一、文档透明加密软件 文档透明加密功能&#xff1a;在不影响单位内部员工对电脑任何正常操作的前提下&#xff0c;文档在复制、新建、修改时被系统强制自动加密。文档只能在单位内部电脑上正常使用&#xff0c;在外部电脑上使用是乱码或无法打…

前端通信(渲染、http、缓存、异步、跨域)自用笔记

SSR/CSR&#xff1a;HTML拼接&#xff1f;网页源码&#xff1f;SEO/交互性 SSR &#xff08;server side render&#xff09;服务端渲染&#xff0c;是指由服务侧&#xff08;server side&#xff09;完成页面的DOM结构拼接&#xff0c;然后发送到浏览器&#xff0c;为其绑定状…

Qt+C++串口调试接收发送数据曲线图

程序示例精选 QtC串口调试接收发送数据曲线图 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对<<QtC串口调试接收发送数据曲线图>>编写代码&#xff0c;代码整洁&#xff0c;规则&…

为何lazada、亚马逊、速卖通卖家都选择自养账号测评?

无论是做亚马逊还是shopee、Lazada、速卖通、wish、煤炉、拼多多Temu、敦煌网、eBay、Etsy、Newegg、美客多、Allegro、阿里国际、poshmark、沃尔玛、joom、OZON等平台。如果想要销量好&#xff0c;免不了进行补单测评的&#xff0c;因为不管对于哪一个平台的店铺新产品而言&am…

探工业互联网的下一站!腾讯云助力智造升级

引言 数字化浪潮正深刻影响着传统工业形态。作为第四次工业革命的重要基石&#xff0c;工业互联网凭借其独特的价值快速崛起&#xff0c;引领和推动着产业变革方向。面对数字化时代给产业带来的机遇与挑战&#xff0c;如何推动工业互联网的规模化落地&#xff0c;加速数字经济…

开利网络受邀参与御盛马术庄园发展专委会主题会议

近日&#xff0c;开利网络受邀参与深度合作客户御盛马术庄园组织的首届发展专委会主体会议&#xff0c;就马术庄园发展方向进行沟通&#xff0c;数字化也是重要议题之一。目前&#xff0c;御盛马术庄园已经完成数字化系统的初步搭建&#xff0c;将通过线上线下相结合的方式搭建…