【QT】贪吃蛇小游戏 -- 童年回忆

成品展示

项目分析:
🐍基本元素如下

🐍小蛇的设计,初始大小蛇头占一个方块,蛇身占两个方块。
🐍关于小蛇的移动,采用蛇头前进方向增加一个方块,蛇尾减掉一个方块的实现方法。
🐍在移动过程中不能立即向前进反方向移动(如正在向左前进的小蛇,按下向右的按键应当无效果),当小蛇吃到食物后,蛇身自增,并记录得分。
🐍当小蛇碰到边界处 或 自身时游戏结束。
🐍食物随机生成。

工程创建

游戏背景图片准备

小游戏的设计采用的是“穿越方案”,到达边界后会从另一边出现。并未设置墙壁碰撞检测。下图墙壁仅为图片,在代码实现过程中可根据需求添加碰撞检测。

主体框架预览

主要函数分析

按键处理

void Widget::keyPressEvent(QKeyEvent* event)
{switch(event->key()){case Qt::Key_Up:if(this->moveFlag != DIR_DOWN){this->moveFlag = DIR_UP;}break;case Qt::Key_Down:if(this->moveFlag != DIR_UP){this->moveFlag = DIR_DOWN;}break;case Qt::Key_Right:if(this->moveFlag != DIR_LEFT){this->moveFlag = DIR_RIGHT;}break;case Qt::Key_Left:if(this->moveFlag != DIR_RIGHT){this->moveFlag = DIR_LEFT;}break;case Qt::Key_Space:if(this->gameStart == false){this->gameStart = true;//游戏开始,启动定时器this->timer->start(TIME);}else{this->gameStart = false;this->timer->stop();}break;default:break;}
}

渲染绘图

//渲染
void Widget::paintEvent(QPaintEvent* et)
{QPainter painter(this);QPen pen;QBrush brush;//背景图片QPixmap pix;pix.load("D:/snake/snake_b1.png");painter.drawPixmap(0,0,820,460,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.drawEllipse(this->rewardNode);//绘制得分QFont font("方正舒体",17,QFont::ExtraLight,false);painter.setFont(font);painter.drawText((this->width() - 75),this->height()- 427, QString::number(this->score));if(checkContact()){painter.drawText((this->width() - 300)/2,(this->height()-30)/2,QString("小蛇不小心咬到了自己,游戏结束!!!"));this->timer->stop();}QWidget::paintEvent(et);
}

槽函数

void Widget::timeout()
{int count = 1;//蛇头是否 触碰到食物if(snake[0].intersects(this->rewardNode)){addNewReword();score++;count++;}while(count--){switch(this->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();
}

蛇运动

以向上运动为例:

情况1:蛇头运动越界,从另一端“穿越”回游戏界面。

情况2:正常运动

运动实现原理:

向上增加方块,代码实现:

void Widget::addTop()
{QPointF leftTop;//左上QPointF rightBotom;//右下//方案1:如果越界(蛇头碰到墙体) -- 游戏失败//方案2:穿墙(上越界,从下边界出来)if(snake[0].y() - NODEHEIGHT < 0){//方案1:游戏直接结束//方案2:穿墙leftTop = QPoint(snake[0].x(),this->height() - NODEHEIGHT);rightBotom = QPoint(snake[0].x()+NODEHEIGHT,this->height());}else{//正常增加方块leftTop = QPointF(snake[0].x(),snake[0].y()-NODEHEIGHT);rightBotom = snake[0].topRight();}snake.insert(0,QRectF(leftTop,rightBotom));
}

整体代码   

widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QList>
#include <Qtime>
QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACEtypedef enum DIR
{DIR_LEFT,DIR_RIGHT,DIR_UP,DIR_DOWN
}dir_t;//超时时间 单位毫秒
#define TIME 100
#define NODEHEIGHT 20//y轴边界
#define BORDER_X 300
//x轴边界
#define BORDER_Y 500class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();//槽函数
protected slots://定时器启动 触发该槽函数void timeout();
protected://上 -- 蛇身增长void addTop();//下 -- 蛇身增长void addDown();//左 -- 蛇身增长void addRight();//右 -- 蛇身增长void addLeft();//删除蛇尾方块void deleteLast();//随机生成食物void addNewReword();//渲染void paintEvent(QPaintEvent* event);//蛇头碰到蛇身判断bool checkContact();//按键处理 -- 重写void keyPressEvent(QKeyEvent* event);
private:Ui::Widget *ui;//记录当前头部朝向int moveFlag = DIR_UP;//游戏是否开始bool gameStart = false;//记录蛇身体QList<QRectF> snake;//定时器QTimer* timer;//食物QRectF rewardNode;//积分int score;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QKeyEvent>
#include <QTimer>
#include <QPainter>
#include <QPaintEvent>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//初始化定时器this->timer = new QTimer();//信号和槽connect(timer,SIGNAL( timeout() ),this,SLOT( timeout() ));//调整窗口带下this->resize(820,460);//初始化蛇身QPointF leftTop = QPointF(200,200);QPointF rightBotom = QPointF(220,220);snake.insert(0,QRectF(leftTop,rightBotom));//初始化食物addNewReword();//初始化积分this->score = 0;addTop();addTop();
}Widget::~Widget()
{delete ui;
}void Widget::keyPressEvent(QKeyEvent* event)
{switch(event->key()){case Qt::Key_Up:if(this->moveFlag != DIR_DOWN){this->moveFlag = DIR_UP;}break;case Qt::Key_Down:if(this->moveFlag != DIR_UP){this->moveFlag = DIR_DOWN;}break;case Qt::Key_Right:if(this->moveFlag != DIR_LEFT){this->moveFlag = DIR_RIGHT;}break;case Qt::Key_Left:if(this->moveFlag != DIR_RIGHT){this->moveFlag = DIR_LEFT;}break;case Qt::Key_Space:if(this->gameStart == false){this->gameStart = true;//游戏开始,启动定时器this->timer->start(TIME);}else{this->gameStart = false;this->timer->stop();}break;default:break;}
}//渲染
void Widget::paintEvent(QPaintEvent* et)
{QPainter painter(this);QPen pen;QBrush brush;//背景图片QPixmap pix;pix.load("D:/snake/snake_b1.png");painter.drawPixmap(0,0,820,460,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.drawEllipse(this->rewardNode);//绘制得分QFont font("方正舒体",17,QFont::ExtraLight,false);painter.setFont(font);painter.drawText((this->width() - 75),this->height()- 427, QString::number(this->score));if(checkContact()){painter.drawText((this->width() - 300)/2,(this->height()-30)/2,QString("小蛇不小心咬到了自己,游戏结束!!!"));this->timer->stop();}QWidget::paintEvent(et);
}void Widget::addTop()
{QPointF leftTop;//左上QPointF rightBotom;//右下//方案1:如果越界(蛇头碰到墙体) -- 游戏失败//方案2:穿墙(上越界,从下边界出来)if(snake[0].y() - NODEHEIGHT < 0){//方案1:游戏直接结束//方案2:穿墙leftTop = QPoint(snake[0].x(),this->height() - NODEHEIGHT);rightBotom = QPoint(snake[0].x()+NODEHEIGHT,this->height());}else{//正常增加方块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()+NODEHEIGHT,NODEHEIGHT);}else{//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() - NODEHEIGHT < 0)//越界{//修正坐标leftTop = QPointF(this->width()-NODEHEIGHT,snake[0].y());}else{leftTop = snake[0].topLeft() - QPointF(NODEHEIGHT,0);}rightBotom = leftTop + QPointF(NODEHEIGHT,NODEHEIGHT);snake.insert(0,QRectF(leftTop,rightBotom));
}
void Widget::addRight()
{QPointF leftTop;QPointF rightBotom;if(snake[0].x() + NODEHEIGHT*2 > this->width())//越界{//修正坐标leftTop = QPointF(0,snake[0].y());}else{//leftTop = snake[0].topRight();}rightBotom = leftTop + QPointF(NODEHEIGHT,NODEHEIGHT);snake.insert(0,QRectF(leftTop,rightBotom));
}void Widget::deleteLast()
{snake.removeLast();
}void Widget::timeout()
{int count = 1;//蛇头是否 触碰到食物if(snake[0].intersects(this->rewardNode)){addNewReword();score++;count++;}while(count--){switch(this->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::addNewReword()
{rewardNode = QRectF(qrand()%(this->width()/20) * 20,qrand()% (this->height()/20) * 20,NODEHEIGHT,NODEHEIGHT);
}bool Widget::checkContact()
{for(int i = 0;i<snake.length();++i){for(int j = i+1;j<snake.length();++j){if(snake[i] == snake[j]){return true;}}}return false;
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java中的常用API

常用API Object类浅克隆与深克隆 ObjectsObjects中的equals 包装类StringBuilder和StringBufferStringBuilder是可变字符串对象StringBuffer线程安全案例![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/87649c20e6464113a42aee5f16f1ee22.png) StringJoiner Object…

【自然语言处理】P2 PyTorch 基础 - 张量

目录 安装 PyTorch张量创建张量操作张量索引、切片、联合操作 CUDA张量 本系列博文我们将使用 PyTorch 来实现深度学习模型等。PyTorch 是一个开源的、社区驱动的深度学习框架。拥有强大的工具和库生态系统&#xff0c;包含 TorchVision&#xff08;用于图像处理&#xff09;、…

创建型模式-单例模式:定义、实现及应用

目录 一、模式定义二、针对问题1.解决的问题2.解决方案3.举个例子4.设计模式适合场景5.实现方式6.优缺点7.与其他模式的关系 三、代码实现 一、模式定义 单例模式&#xff08;Singleton Pattern&#xff09;是一种创建型模式&#xff0c;用于限制某个类只能创建一个对象。它提…

数仓建模维度建模理论知识

0. 思维导图 第 1 章 数据仓库概述 1.1 数据仓库概述 数据仓库是一个为数据分析而设计的企业级数据管理系统。数据仓库可集中、整合多个信息源的大量数据&#xff0c;借助数据仓库的分析能力&#xff0c;企业可从数据中获得宝贵的信息进而改进决策。同时&#xff0c;随着时间的…

压力测试工具-Jmeter使用总结

目录 一.前言 二.线程组 三.线程组的组件 四.线程组-HTTP请求 1、JSON提取器 2、XPATH提取器 3、正则表达式提取器 五.线程组-断言 1、响应断言 2、JSON断言 六.创建测试 1.创建线程组 2.配置元件 3.构造HTTP请求 4.添加HTTP请求头 5.添加断言 6.添加查看结果树…

数仓治理-存储资源治理

目录 一、存储资源治理的背景 二、存储资源治理的流程及思路 三、治理前如何评估 3.1 无用数据表/临时数据表下线评估 3.2 表及分区的生命周期评估 3.3 存储及压缩格式评估 3.4 根据业务场景实现节省存储评估 四、治理后的成效如何评估 一、存储资源治理的背景 由于早…

人工智能深度学习发展历程-纪年录

前言 为了理解模型之间的改进关系、明确深度学习的发展目标、提高自身对模型的深度理解、贯彻爱与和平的理念。总之&#xff0c;我做了如下表格。 时间 重大突破 模型改进 详细信息 1847 SGD 随机梯度下降 1995 SVM 支持向量机 1982 RNN 循环神经网络&#xff0c;…

[晓理紫]每日论文分享(有中文摘要,源码或项目地址)--大模型、扩散模型、视觉

专属领域论文订阅 关注{晓理紫|小李子}&#xff0c;每日更新论文&#xff0c;如感兴趣&#xff0c;请转发给有需要的同学&#xff0c;谢谢支持 如果你感觉对你有所帮助&#xff0c;请关注我&#xff0c;每日准时为你推送最新论文。 为了答谢各位网友的支持&#xff0c;从今日起…

springboot在线问诊系统-计算机毕业设计源码00211

摘 要 针对医院门诊等问题&#xff0c;对在线问诊进行研究分析&#xff0c;然后开发设计出在线问诊系统以解决问题。在线问诊系统主要功能模块包括首页、轮播图管理、公告信息管理、资源管理、系统用户管理&#xff08;管理员、患者用户、医生用户&#xff09;、模块管理&#…

Vue 环境准备

1.安装vscode https://code.visualstudio.com/ 2.安装开发vue所需插件&#xff1a; Vetur —— 语法高亮、智能感知、Emmet等 包含格式化功能&#xff0c; AltShiftF &#xff08;格式化全文&#xff09;&#xff0c;CtrlK CtrlF&#xff08;格式化选中 代码&#xff0c;两…

[C语言] 指针详解(1)

一. 指针 利用指针,可以找到相对应内存地址(唯一的一段编号),从而定位数据. (通俗来说,指针就是变量,用来存放内存单元的地址) 保存一段 16进制的 地址编号 二、指针类型/变量: 类型: 基础类型* 如: int* char*指针变量: int* pa pa就为指针变…

Shopee越南本土店好做吗?越南本土Shopee店家如何收款?站斧浏览器

Shopee越南本土店好做吗&#xff1f; 对于越南本土的Shopee店家来说&#xff0c;他们可能会关心Shopee平台的运营情况和是否适合他们开展电商业务。那么&#xff0c;Shopee好做吗&#xff1f;以下是一些相关的讨论点。 用户基础和市场规模 作为东南亚地区最大的电商平台之一…