Qt:26.Qt项目:贪吃蛇游戏

news2024/11/22 22:55:05

一、项目功能演示:

  • 开始界面可以点击进入游戏。

        

  • 点击进入游戏之后,切换到选项界面,该界面可以选择游戏难度,回退,以及查询最近一次游戏得分。

        

  • 游戏具体界面如下。贴图啥的可以自己换,本人审美不咋行,随便找的贴图。

        

        

二、文件展示:

三、项目代码:

1.打开窗口实现:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPushButton>
#include <QLabel>
#include <QFont>
#include <QSound>
#include "gameselect.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    //初始化窗口,标题,图标,窗口大小
    ui->setupUi(this);
    this->setWindowTitle("贪吃蛇");
    this->setWindowIcon(QIcon(":/image/pix.png"));
    this->setFixedSize(600,400);

    //窗口背景设置,将图片设置自动拉伸
    QLabel* label=new QLabel(this);
    label->setGeometry(0,0,this->width(),this->height());
    label->setPixmap(QPixmap(":/image/enter.jpg"));
    label->setScaledContents(true);

    //设置进入按钮
    QPushButton* enter_but=new QPushButton(this);
    enter_but->move(250,250);
    enter_but->setText("进入游戏");
    enter_but->setStyleSheet("QPushButton{border:0px;color:red;}");

    //按钮文本设置
    QFont font("华文行楷",18);
    enter_but->setFont(font);

    //创建选项页面,设置点击音效,打开新窗口,关闭旧窗口
    GameSelect* gameSelect=new GameSelect;
    connect(enter_but,&QPushButton::clicked,[=]()
    {
        gameSelect->setGeometry(this->geometry());
        QSound::play(":/image/6.wav");
        gameSelect->show();
        this->close();

    });

}

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

2.选项窗口实现:

#include "gameselect.h"
#include <QIcon>
#include <QLabel>
#include <QDebug>
#include <QVBoxLayout>
#include <QPushButton>
#include <QFont>
#include "mainwindow.h"
#include <QSound>
#include "gameroom.h"
#include <QFile>

GameSelect::GameSelect(QWidget *parent) : QWidget(parent)
{

    //窗口大小固定,设置图标,标题
    this->setFixedSize(600,400);
    this->setWindowTitle("关卡选择");
    this->setWindowIcon(QIcon(":/image/pix.png"));

    //加载背景
    QLabel* label=new QLabel(this);
    label->setGeometry(this->geometry());
    label->setPixmap(QPixmap(":/image/load.jpg"));

    //创建一个widget对象存放布局管理器,管理选项按钮
    QWidget* widget=new QWidget(this);
    widget->setGeometry(150,100,300,250);

    //创建布局管理器,并将它设置到widget对象
    QVBoxLayout* layout=new QVBoxLayout;
    widget->setLayout(layout);

    //选项按钮创建
    QPushButton* but_easy=new QPushButton("简单模式");
    QPushButton* but_normal=new QPushButton("正常模式");
    QPushButton* but_diff=new QPushButton("困难模式");
    QPushButton* but_grades=new QPushButton("战绩查询");
    QPushButton* but_ret=new QPushButton("返回上页");

    //按钮添加到布局管理器
    layout->addWidget(but_easy);
    layout->addWidget(but_normal);
    layout->addWidget(but_diff);
    layout->addWidget(but_grades);
    layout->addWidget(but_ret);

    //设置按钮的拉伸策略,是的可以占满整个布局管理器
    but_easy->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    but_normal->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    but_diff->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    but_grades->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    but_ret->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);

    QFont font("华文行楷",25);
    widget->setFont(font);

    //设置按钮无边框,文本显示颜色为蓝色
    but_easy->setStyleSheet("QPushButton{border: 0px;color:blue;}");
    but_normal->setStyleSheet("QPushButton{border: 0px;color:blue;}");
    but_diff->setStyleSheet("QPushButton{border: 0px;color:blue;}");
    but_grades->setStyleSheet("QPushButton{border: 0px;color:blue;}");
    but_ret->setStyleSheet("QPushButton{border: 0px;color:blue;}");


    //连接按钮和槽函数,直接使用lambda表达式
    connect(but_ret,&QPushButton::clicked,[=]()
    {
       MainWindow* mainwindow=new MainWindow;
       QSound::play(":/image/6.wav");
       mainwindow->show();
       this->close();
    });

    GameRoom* room=new GameRoom;
    connect(but_easy,&QPushButton::clicked,[=]()
    {

        room->setGeometry(this->geometry());
        QSound::play(":/image/6.wav");
        room->show();
        this->close();

        room->setMoveTimeout(300);

    });

    connect(but_normal,&QPushButton::clicked,[=]()
    {
        room->setGeometry(this->geometry());
        QSound::play(":/image/6.wav");
        room->show();
        this->close();
        room->setMoveTimeout(200);

    });

    connect(but_diff,&QPushButton::clicked,[=]()
    {
        room->setGeometry(this->geometry());
        QSound::play(":/image/6.wav");
        room->show();
        this->close();
        room->setMoveTimeout(100);
    });

    connect(but_grades, &QPushButton::clicked, [=]() {
        QSound::play(":/image/6.wav");
        QWidget* widget = new QWidget;
        widget->setWindowTitle("历史分数");
        widget->setWindowIcon(QIcon(":/image/pix.png"));
        widget->setFixedSize(400, 200);
        QLabel* label=new QLabel(widget);
        label->setGeometry(0,0,400,200);

        QFile file("C:/Users/86133/Desktop/Qt-tmp.txt");
        file.open(QIODevice::ReadOnly);
        QTextStream in(&file);
        QString grade=in.readLine();

        QFont font("行书",30);
        label->setFont(font);

        label->setText("最近得分:"+ grade);
        widget->show();
    });

}

3.游戏窗口实现

#include "gameroom.h"
#include <QIcon>
#include <QPainter>
#include <QTimer>
#include <QPushButton>
#include <QMessageBox>
#include "gameselect.h"
#include <QFile>
#include <QTextStream>
#include <QShortcut>

GameRoom::GameRoom(QWidget *parent) : QWidget(parent)
{
    
    //初始化窗口,标题,图标,大小
    this->setWindowTitle("游戏房间");
    this->setWindowIcon(QIcon(":/image/pix.png"));
    this->setFixedSize(600,400);

    //尾插一个节点作为头节点
    snakeList.push_back(QRectF(160,220,kSnakeNodeWidth,kSnakeNodeHeight));
    moveUp();
    moveUp();

    //创建食物
    createFood();

    //定时器设置
    timer=new QTimer(this);
    connect(timer,&QTimer::timeout,[=]()
    {
        //如果吃到食物,重新生成食物
        int cnt=1;
        if(snakeList.front().intersects(foodRect))
        {
            createFood();
            cnt++;
        }

        //通过食物数量,控制移动的距离
        while(cnt--)
        {
            switch (moveDirect)
            {
            case SnakeDirect::UP:
                moveUp();
                break;
            case SnakeDirect::DOWN:
                moveDown();
                break;
            case SnakeDirect::LEFT:
                moveLeft();
                break;
            case SnakeDirect::RIGHT:
                moveRight();
                break;
            }
        }
        snakeList.pop_back();
        update();
    });

    
    //开始和暂停按钮
    QPushButton* sta_but=new QPushButton("开始游戏",this);
    QPushButton* stop_but=new QPushButton("暂停游戏",this);

    sta_but->move(450,100);
    stop_but->move(450,150);

    QFont font("楷体",15);
    sta_but->setFont(font);
    stop_but->setFont(font);

    //开始功能实现,音乐播放,音乐持续播放设置
    connect(sta_but,&QPushButton::clicked,[=]()
    {
        isGameStart=true;
        timer->start(moveTimeout);
        sound=new QSound(":/image/2.wav");
        sound->play();
        sound->setLoops(-1);
    });

    connect(stop_but,&QPushButton::clicked,[=]()
    {
        isGameStart=false;
        timer->stop();
        sound->stop();
    });

    //移动按钮设置
    QPushButton* up=new QPushButton("↑",this);
    QPushButton* down=new QPushButton("↓",this);
    QPushButton* left=new QPushButton("←",this);
    QPushButton* right=new QPushButton("→",this);

    up->move(480,230);
    down->move(480,270);
    left->move(440,250);
    right->move(520,250);

    up->setStyleSheet("QPushButton{border:0px}");
    down->setStyleSheet("QPushButton{border:0px}");
    left->setStyleSheet("QPushButton{border:0px}");
    right->setStyleSheet("QPushButton{border:0px}");

    QFont ft("楷体",25);
    up->setFont(ft);
    down->setFont(ft);
    left->setFont(ft);
    right->setFont(ft);

    QShortcut* s1=new QShortcut(QKeySequence("W"),up);
    QShortcut* s2=new QShortcut(QKeySequence("S"),down);
    QShortcut* s3=new QShortcut(QKeySequence("A"),left);
    QShortcut* s4=new QShortcut(QKeySequence("D"),right);

    QObject::connect(s1,&QShortcut::activated,up,&QPushButton::click);
    QObject::connect(s2,&QShortcut::activated,down,&QPushButton::click);
    QObject::connect(s3,&QShortcut::activated,left,&QPushButton::click);
    QObject::connect(s4,&QShortcut::activated,right,&QPushButton::click);

    connect(up,&QPushButton::clicked,[=]()
    {
        if(moveDirect!=SnakeDirect::DOWN)
            moveDirect=SnakeDirect::UP;
    });

    connect(down,&QPushButton::clicked,[=]()
    {
        if(moveDirect!=SnakeDirect::UP)
            moveDirect=SnakeDirect::DOWN;
    });

    connect(left,&QPushButton::clicked,[=]()
    {
        if(moveDirect!=SnakeDirect::RIGHT)
            moveDirect=SnakeDirect::LEFT;
    });

    connect(right,&QPushButton::clicked,[=]()
    {
        if(moveDirect!=SnakeDirect::LEFT)
            moveDirect=SnakeDirect::RIGHT;
    });

    //退出按钮
    QPushButton* exit_but=new QPushButton("退出游戏",this);
    exit_but->move(450,350);
    exit_but->setFont(font);

    QMessageBox* msg=new QMessageBox(this);
    QPushButton* ok=new QPushButton("ok");
    QPushButton* cancel=new QPushButton("cancel");
    msg->addButton(ok,QMessageBox::AcceptRole);
    msg->addButton(cancel,QMessageBox::RejectRole);
    msg->setWindowTitle("退出");
    msg->setText("是否确定退出?");

    connect(exit_but,&QPushButton::clicked,[=]()
    {
        msg->exec();
        QSound::play(":/image/6.wav");
        if(msg->clickedButton()==ok)
        {
            GameSelect* gameselect=new GameSelect;
            gameselect->show();
            this->close();
        }
        else
        {
            msg->close();
        }
    });


}

void GameRoom::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    QPixmap pix;
    pix.load(":/image/main.jpg");
    painter.drawPixmap(0,0,400,400,pix);
    pix.load(":/image/control.jpg");
    painter.drawPixmap(400,0,200,400,pix);

    //绘制蛇头
    if(moveDirect==SnakeDirect::UP)
        pix.load(":/image/up.png");
    else if(moveDirect==SnakeDirect::DOWN)
        pix.load(":/image/down.png");
    else if(moveDirect==SnakeDirect::LEFT)
        pix.load(":/image/left.png");
    else
        pix.load(":/image/right.png");
    auto snakeHead=snakeList.front();
    painter.drawPixmap(snakeHead.x(),snakeHead.y(),snakeHead.width(),snakeHead.height(),pix);

    //绘制蛇身
    pix.load(":/image/circle.png");
    for(int i=1;i<snakeList.size()-1;i++)
    {
        auto node=snakeList.at(i);
        painter.drawPixmap(node.x(),node.y(),node.width(),node.height(),pix);

    }

    //绘制蛇尾
    auto snakeTail=snakeList.back();
    painter.drawPixmap(snakeTail.x(),snakeTail.y(),snakeTail.width(),snakeTail.height(),pix);

    //绘制食物
    pix.load(":/image/Hamburg.png");
    painter.drawPixmap(foodRect.x(),foodRect.y(),kSnakeNodeWidth,kSnakeNodeHeight,pix);

    //将分数绘制到界面
    QPen pen;
    pen.setColor(Qt::black);
    painter.setPen(pen);
    QFont font("楷体",15);
    painter.setFont(font);

    painter.drawText(430,30,"当前等分:");
    painter.drawText(530,30,QString("%1").arg(snakeList.size()-3));

    //绘制失败效果
    if(checkFail())
    {
        pen.setColor(Qt::red);
        QFont font("楷体",30);
        painter.setPen(pen);
        painter.setFont(font);
        painter.drawText(100,180,"Game Over");
        timer->stop();
        sound->stop();
    }

    //将当前分数保存到文件中
    int c=snakeList.size()-3;
    QFile file("C:/Users/86133/Desktop/Qt-tmp.txt");
    if(file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        QTextStream out(&file);
        int num=c;
        out<<num;
        file.close();
    }


}

void GameRoom::moveUp()
{
    QPointF leftTop;
    QPointF rightBottom;
    auto snakeHead=snakeList.front();
    int headX=snakeHead.x();
    int headY=snakeHead.y();

    if(headY<20)
    {
        leftTop=QPointF(headX,this->height()-kSnakeNodeHeight);
    }
    else
    {
        leftTop=QPointF(headX,headY-kSnakeNodeHeight);
    }
    rightBottom=leftTop+QPointF(kSnakeNodeWidth,kSnakeNodeHeight);
    snakeList.push_front(QRectF(leftTop,rightBottom));
}

void GameRoom::moveDown()
{
    QPointF leftTop;
    QPointF rightBottom;
    auto snakeHead=snakeList.front();
    int headX=snakeHead.x();
    int headY=snakeHead.y();

    if(headY>this->height()-40)
    {
        leftTop=QPointF(headX,0);
    }
    else
    {
        leftTop=snakeHead.bottomLeft();
    }
    rightBottom=leftTop+QPointF(kSnakeNodeWidth,kSnakeNodeHeight);
    snakeList.push_front(QRectF(leftTop,rightBottom));
}

void GameRoom::moveLeft()
{
    QPointF leftTop;
    QPointF rightBottom;
    auto snakeHead=snakeList.front();
    int headX=snakeHead.x();
    int headY=snakeHead.y();

    if(headX<20)
    {
        leftTop=QPointF(400-kSnakeNodeWidth,headY);
    }
    else
    {
        leftTop=QPointF(headX-kSnakeNodeWidth,headY);
    }
    rightBottom=leftTop+QPointF(kSnakeNodeWidth,kSnakeNodeHeight);
    snakeList.push_front(QRectF(leftTop,rightBottom));
}

void GameRoom::moveRight()
{
    QPointF leftTop;
    QPointF rightBottom;
    auto snakeHead=snakeList.front();
    int headX=snakeHead.x();
    int headY=snakeHead.y();

    if(headX>360)
    {
        leftTop=QPointF(0,headY);
    }
    else
    {
        leftTop=snakeHead.topRight();
    }
    rightBottom=leftTop+QPointF(kSnakeNodeWidth,kSnakeNodeHeight);
    snakeList.push_front(QRectF(leftTop,rightBottom));
}

bool GameRoom::checkFail()
{
    for(int i=0;i<snakeList.size();i++)
    {
        for(int j=i+1;j<snakeList.size();j++)
        {
            if(snakeList.at(i)==snakeList.at(j))
            {
                return true;
            }
        }
    }
    return false;
}

void GameRoom::createFood()
{
    foodRect=QRectF(qrand()%(400/kSnakeNodeWidth)*kSnakeNodeWidth,
                    qrand()%(400/kSnakeNodeHeight)*kSnakeNodeHeight,kSnakeNodeWidth,kSnakeNodeHeight);
}


需要项目的源文件,私发。

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

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

相关文章

SPA Fiori开发实战课程(一)

前言 由于工作需要&#xff0c;对Fiori的开发有了一些具体实践&#xff0c;所以做一些记录和总结。 准备工作 1. 对前端有一定的了解&#xff0c;熟悉Node.js&#xff0c;Vue等前端服务器和基础框架。 2. 后端使用ABAP系统。 3. 使用Visual Studio Code进行开发。 工程搭建 打…

TIMO后台管理系统:基于SpringBoot2.0的模块化快速开发平台

摘要 随着软件技术的快速发展&#xff0c;后台管理系统的构建成为企业级应用的重要组成部分。本文旨在介绍TIMO后台管理系统的设计与实现&#xff0c;该系统基于Spring Boot 2.0、Spring Data JPA、Thymeleaf和Shiro等主流技术构建&#xff0c;采用模块化设计以简化开发和维护…

第2章 矩阵

A 乘以此列向量&#xff0c;1的位置依次往下&#xff0c;所以A的列向量全为0 B C、D 取BE 要统一

设计模式——模版方法和策略模式

前言 作为一名资深CV工程师&#xff0c;学会为自己减少工作量乃重中之重。但只是一味地CV&#xff0c;只会因为劣质代码而让自己的工作量加倍&#xff0c;为了将来不被繁重的维护工作而打扰自己的休息日&#xff0c;为了更好的节能&#xff0c;学习设计模式&#xff0c;刻不容缓…

goLang 通过 Select + Channels 实现定时任务与调度

time 包 在与 channel 结合时提供了很多有用的功能,其中 time.Ticker 结构体能够处理定时事件,它会定期在指定 channel 上发送时间值。在这篇文章中,我们深入探讨了如何使用 Go 语言中的 time 包与 channel 结合来处理定时事件和任务调度。通过 time.Ticker 结构体的周期性触…

MySQL(终章)视图, 用户管理, C连接MySQL.

目录 1.视图; 2.用户管理; 1.视图: 1.1 概念和基本操作: 视图本质就是表结构, 虚拟表. 视图和基表数据的改变都会相互影响. 创建视图语法: create view 视图名 as select语句&#xff1b; 修改视图: update set ; 删除视图: drop view 视图名&#xff1b; 1. 2 视图使用规则: …

【java】力扣 跳跃游戏

文章目录 题目链接题目描述代码1.动态规划2.贪心 题目链接 55.跳跃游戏 题目描述 代码 1.动态规划 1.1 dp数组的含义 dp[i]&#xff1a;从[0,i]的任意一点处出发&#xff0c;你最大可以跳跃到的位置。 例如nums[2,3,1,1,4]中: dp[0]2 dp[1]4 dp[2]4 dp[3]4 dp[4]8&#xff…

PACS-医学影像信息管理系统,全影像科室PACS源码,内置包括MPR、CMPR、VR等三维处理功能

PACS系统可以覆盖医院现有放射、CT、MR、核医学、超声、内镜、病理、心电等绝大部分DICOM和非DICOM检查设备&#xff0c;支持从科室级、全院机、集团医院级乃至到区域PACS的平滑扩展&#xff0c;能够与医院HIS、集成平台的有效集成和融合&#xff0c;帮助医院实现了全院医学影像…

大数据-38 Redis 高并发下的分布式缓存 Redis简介 缓存场景 读写模式 旁路模式 穿透模式 缓存模式 基本概念等

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; HadoopHDFSMapReduceHiveFlumeSqoopZookeeperHBaseRedis 章节内容 上一节我们完成了&#xff1a; HBase …

更改若依框架的包名

使用KIT更改 官网&#xff1a;http://www.goldpankit.com 具体步骤 1. 打开KIT官网&#xff0c;选择Ruoyi-Vue框架&#xff0c;如下图所示 2. 点击构建框架按钮&#xff0c;如下图所示 3. 填写框架参数并点击立即构建 4. 下载ZIP并解压即可&#xff0c;构建后内容如下 这样…

《Exploring Aligned Complementary Image Pair for Blind Motion Deblurring》

这篇论文的标题《Exploring Aligned Complementary Image Pair for Blind Motion Deblurring》可以翻译为《探索对齐的互补图像对用于盲运动去模糊》。从标题可以推断,论文的焦点在于开发一种算法或技术,利用成对的图像来解决运动模糊问题,特别是在不知道模糊核(即造成模糊…

基于牛顿-拉夫逊优化算法(Newton-Raphson-based optimizer, NBRO)的无人机三维路径规划

牛顿-拉夫逊优化算法(Newton-Raphson-based optimizer, NBRO)是一种新型的元启发式算法&#xff08;智能优化算法&#xff09;&#xff0c;该成果由Sowmya等人于2024年2月发表在中科院2区Top SCI期刊《Engineering Applications of Artificial Intelligence》上。 1、算法原理…

(vue)Vue读取public中的json文件,打包后只需更改包文件

(vue)Vue读取public中的json文件,打包后只需更改包文件 背景&#xff1a;增加账号需求。原本是在页面&#xff0c;每次都需技术人员添加再打包部署&#xff0c;现在放到json里&#xff0c;以后直接服务器改json就行。 旧版&#xff1a; let userArr [{username:aaa,password:…

系统架构设计师教程 第3章 信息系统基础知识-3.7 企业资源规划(ERP)-解读

系统架构设计师教程 第3章 信息系统基础知识-3.7 企业资源规划&#xff08;ERP&#xff09; 3.7.1 企业资源规划的概念3.7.2 企业资源规划的结构3.7.2.1 生产预测3.7.2.2 销售管理&#xff08;计划&#xff09;3.7.2.3 经营计划&#xff08;生产计划大纲&#xff09;3.7.2.4 …

IDEA双击卡住打不开问题解决

双击idea图标一直卡在这个页面 解决方案: 随便找个文件 edit with intellij idea打开 删除最近安装的插件 apply 然后重启

C++容器之array

C array容器 特点 array是固定大小数组。 C中&#xff0c;array是一个模板类&#xff0c;提供了数组的功能&#xff0c;在许多方面比原始的 C 风格数组更为强大和灵活。 主要特点 固定大小: std::array 的大小在编译时确定&#xff0c;运行时无法修改。包含全部 STL 功能:…

神经网络之循环神经网络

目录 一、循环神经网络概述&#xff1a;1.传统神经网络与循环神经网络的区别&#xff1a;2.循环神经网络定义&#xff1a; 图片来自&#xff1a;深度学习———循环神经网络 一、循环神经网络概述&#xff1a; 1.传统神经网络与循环神经网络的区别&#xff1a; MLP、卷积神经…

【单目3D检测】smoke(1):模型方案详解

纵目发表的这篇单目3D目标检测论文不同于以往用2D预选框建立3D信息&#xff0c;而是采取直接回归3D信息&#xff0c;这种思路简单又高效&#xff0c;并不需要复杂的前后处理&#xff0c;而且是一种one stage方法&#xff0c;对于实际业务部署也很友好。 题目&#xff1a;SMOKE&…

【LabVIEW作业篇 - 4】:属性节点赋值和直接节点赋值的区别体现

文章目录 属性节点赋值和直接节点赋值的区别体现 属性节点赋值和直接节点赋值的区别体现 创建5个圆形指示灯&#xff0c;然后循环点亮&#xff0c;先给圆形指示灯赋值假变量&#xff0c;然后再进行循环。 运行结果&#xff0c;观察结果&#xff0c;发现刚开始运行时&#xff0…

Unity | Shader基础知识(第十九集:顶点着色器的进一步理解-易错点讲解)

目录 一、前言 二、网格 三、方法UnityObjectToClipPos 四、顶点着色器和片元着色器的POSITION 五、作者的碎碎念 一、前言 之前我们简单讲解过顶点着色器&#xff0c;也简单讲解了表面着色器&#xff0c;并且一起做了一些案例&#xff0c;因为顶点着色器本身是更自由一些…