Qt6_贪吃蛇Greedy Snake
贪吃蛇Greedy Snake
1分析
首先这是一个贪吃蛇界面,由一个长方形边框和一只贪吃蛇组成

默认开局时,贪吃蛇身体只有3个小方块,使用画笔画出
1.1如何移动
对于蛇的移动,有2种方法
- 在一定时间范围内(定时器),未对游戏做出操作(前后左右移动),则整个身体向面朝方向移动一格
- 在一定时间范围内(定时器),未对游戏做出操作(前后左右移动),则身体最前面加上一格方块,身体最后面减去一个方块
这里使用第2种方法
如图,有4个坐标,AC分别是原蛇的头部方格的两个坐标
则新产生的方格的B点为(x1,y1-方格高度);D点(x3,y3-方格高度)

注意
向某个方向增加不能无限增加下去,当触碰到顶部时,我们可以设置条件:
- 死亡
- 穿过从另一个方向开始
这里我们采用第2种方式
1.2向上
如图,此时BD点已经超过x轴,即高度为0的位置

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

-
移动前:x3=x1+蛇宽度;y3=y1
-
移动后:x2=x1,y2=窗口高度-蛇宽度;x4=x2+蛇宽度,y4=y2
1.3向下
同理,向下走只要最下面增加,最上面减少即可

-
移动前: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

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

1.5向右
-
移动前:x4=x1+蛇宽;y4=y1+蛇高
-
移动后:x2=x1+蛇宽,y2=y1;x3=x4+蛇宽,y3=y4

穿越
- x2=0,y2=y1;
- x3=蛇宽,y3=y4

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

判断球是否被吃掉:即判断蛇的身体是否与球重合,如果重合,增加身体1,同时刷新球出现的位置
3代码
widget.h
#ifndef WIDGET_H
#define WIDGET_H#define OUTTIME 100 //超时时间
#define SNAKE_WIDTH 20 //蛇的一个方格宽度
#define SNAKE_HEIGHT 20 //蛇的一个方格高度
#include <QWidget>
#include<QKeyEvent>
#include<QDebug>
#include<QTimer>
#include<QPixmap>
#include<QPainter>
#include<random>
#include<QTime>
#include <QRandomGenerator>/*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<QRectF> snake;
protected slots:void timeOut();//超时函数
};
#endif // WIDGET_H
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); //蛇身+1addTOP(); //蛇身+1addTOP();//初始化食物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 0rightBotom = 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;i<snake.length();i++){painter.drawRect(snake[i]);//画家进行绘画}//绘制食物brush.setColor(Qt::yellow);//画刷颜色brush.setStyle(Qt::SolidPattern);//画刷风格painter.setPen(pen); //画家配置画笔painter.setBrush(brush);//画家配置画刷painter.drawEllipse(food);//绘制结束面板if(isIntersect()){QFont font("微软雅黑",30,QFont::ExtraLight,false);painter.setFont(font);painter.drawText(this->width()/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<snake.length();i++){if(snake[0] == snake[i]){return true;}}return false;
}//超时函数
void Widget::timeOut()
{int count =1;if(snake[0].intersects(food)){count++;//重新初始化食物,即令其刷新位置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效果
//重新初始化食物,即令其刷新位置
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效果
相关文章:
Qt6_贪吃蛇Greedy Snake
贪吃蛇Greedy Snake 1分析 首先这是一个贪吃蛇界面,由一个长方形边框和一只贪吃蛇组成 默认开局时,贪吃蛇身体只有3个小方块,使用画笔画出 1.1如何移动 对于蛇的移动,有2种方法 在一定时间范围内(定时器),未对游戏…...
Credo推出业界首款单片集成CMOS VCSEL驱动器的800G光DSP芯片
针对AOC及短距(SR)光模块优化的新型Credo DSP,适用于下一代超大规模数据中心/AI应用 加州圣何塞和中国深圳,2023年9月6日——Credo Technology(纳斯达克股票代码:CRDO)今日发布两款新品&#x…...
【经验分享】如何使用VSCode对比两个文件
问题: 当有两个不同版本的文件,如何使用VSCode对比两个文件 解决办法 长按ctrl选择想要对比的两个文件-----右键选择将已选项进行比较----大功告成 大功告成...
从裸机开始安装ubuntu系统到安装NVIDIA驱动
这篇文章为总结类文章,更多的是把各个博主的内容总结一下,形成一套端到端的方法,主要内容包括: 安装ubuntu22.04版本(含启动U盘制作)配置ssh、固定ip和端口号安装NVIDIA驱动安装cuda11.7和cudnn8.6 文章目录 一、安装ubuntu22.041…...
索尼 toio™ 应用创意开发征文|小巧机器,大无限,探索奇妙世界
文章目录 前言微型机器人的未来:toio™小机器人简介toio™小机器人:创新功能一览toio™小机器人:多领域的变革者toio™小机器人贪吃蛇游戏代码实现写在最后 前言 当我们谈到现代科技的创新时,往往会联想到复杂的机器和高级的编程…...
什么牌子的led台灯质量好?热门的Led护眼台灯推荐
led台灯有环保无污染、耗能低、长寿命等优点,适合用在阅读、书写、批阅等办公或学习的场所。而挑选LED台灯时,分散光挡板做的比较好的优先选择,能分散大量蓝光,对眼睛危害较小。下面,小编为大家推荐五款质量好的led护眼…...
预推免,保研------长安大学保内,附加分面试准备【记录帖】
🚀长安大学——人工智能系——程惠泽 🚌前六学期专业排名:7/82 🚌信息门户GPA:3.94 🚌平均成绩:89.83 🚌加权成绩:89.15 / ☁️本人比较菜,只能保研本校&…...
Linux开源防病毒引擎ClamAV
ClamAV官方地址:https://www.clamav.net 它支持Linux、BSD、windows、Mac OS X等系统。 在CentOS 8(Tencent OS 3.1)安装非常便利,可以使用yum。 yum install clamav 安装成功,就可以使用它进行病毒扫描检查了。 c…...
Java复习-25-单例设计模式
单例设计模式 目的(使用场景) 在实际开发下,会存在一种情况:某一种类在程序的整个生命周期中,只需要实例化一次就足够了。例如,系统数据类,由于操作系统只有一个,因此在程序初始化…...
博客系统自动化测试项目实战(测试系列9)
目录 前言: 1.博客前端页面测试用例图 2.测试用例的代码实现 2.1登录页面的测试 2.2博客列表页面的测试 2.3写博客测试 2.4博客详情页面的测试 2.5已发布博客的标题和时间的测试 2.6注销用户的测试 结束语: 前言: 之前小编给大家讲…...
华纳云:Linux的底层体系结构是怎样的
Linux操作系统的底层体系结构是一个开源的Unix-like操作系统内核,通常称为Linux内核(Linux Kernel)。下面是Linux底层体系结构的主要组成部分和工作原理: 内核(Kernel): Linux的核心部分是内核,它是操作系统…...
SpringMVC常用注解介绍及参数传递说明
前言 上一篇文章介绍了SpringMVC是什么以及它的工作流程和核心组件,介绍入门示例时,提到了RequestMapping注解,那么这篇文章就来介绍SpringMVC中更多的常用的注解,以及它的参数传递。 一. SpringMVC常用注解 1.1 RequestParam …...
4 个你可能不知道的 Python 迭代工具过滤器函数
推荐:使用 NSDT场景编辑器 快速搭建3D应用场景 当您只想循环遍历迭代器、检索序列中的元素并处理它们时,这些元素特别有用 - 所有这些都无需将它们存储在内存中。今天我们将学习如何使用以下四个迭代工具过滤器函数: filterfalsetakewhiledr…...
Scrapy简介-快速开始-项目实战-注意事项-踩坑之路
scrapy项目模板地址:https://github.com/w-x-x-w/Spider-Project Scrapy简介 Scrapy是什么? Scrapy是一个健壮的爬虫框架,可以从网站中提取需要的数据。是一个快速、简单、并且可扩展的方法。Scrapy使用了异步网络框架来处理网络通讯&…...
lightdb 支持兼容Oracle的to_clob函数
文章目录 概述案例演示 概述 在信创移植的SQL语句中,有来源于Oracle数据库的SQL语句。 在ORACLE PL/SQL包中,你可以使用TO_CLOB(character)函数将RAW、CHAR、VARCHAR、VARCHAR2、NCHAR、NVARCHAR2、CLOB值转换为CLOB。 因此在LightDB 23.3版本中实现了…...
ES6中let和const关键字与var关键字之间的区别?
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 变量作用域(Scope):⭐ 变量提升(Hoisting):⭐ 重复声明:⭐ 初始化:⭐ 全局对象属性:⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#…...
Python中的异常处理3-1
Python中的异常指的是语法上没有错误,但是代码执行时会导致错误的情况。 1 抛出异常 在图1所示的代码中,要求用户输入一个数字,该代码在语法上没有错误。 图1 出现异常的代码 但是运行该代码之后,如果用户输入的是数字…...
大数据与AI:解析智慧城市的幕后英雄
文章目录 1. 智慧城市的定义与发展2. 大数据:智慧城市的基石2.1 大数据的概念与重要性2.2 大数据的应用案例2.2.1 智能交通管理2.2.2 能源效率优化2.2.3 城市规划与土地利用 3. 人工智能:智慧城市的大脑3.1 人工智能的概念与重要性3.2 人工智能的应用案例…...
将钉钉机器人小程序从一个公司迁移至另一个公司的步骤
引言: 由于我们以前开发的钉钉小程序都在一个公司,想在想应用到另一个公司,这就牵扯出了关于钉钉小程序迁移方面的具体步骤。下面是具体步骤: 1、创建一个钉钉小程序 在这一步你需要有钉钉开放平台的开发者权限,具体…...
j解决Ubuntu无法安装pycairo和PyGObject
环境:虚拟机Ubuntu20.04,vscode无法安装pycairo和PyGObject 虚拟机Ubuntu20.04,vscode中运行Anaconda搭建的vens 的Python3.8.10 首先在vscode中点击ctrlshiftp,选择Python3.8.10的环境,自动激活Python 最近在搞无人…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...
