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

2024-02-03 08:04

本文主要是介绍【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;
}

这篇关于【QT】贪吃蛇小游戏 -- 童年回忆的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/673468

相关文章

VS配置好Qt环境之后但无法打开ui界面的问题解决

《VS配置好Qt环境之后但无法打开ui界面的问题解决》本文主要介绍了VS配置好Qt环境之后但无法打开ui界面的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 目UKeLvb录找到Qt安装目录中designer.UKeLvBexe的路径找到vs中的解决方案资源

Qt之QMessageBox的具体使用

《Qt之QMessageBox的具体使用》本文介绍Qt中QMessageBox类的使用,用于弹出提示、警告、错误等模态对话框,具有一定的参考价值,感兴趣的可以了解一下... 目录1.引言2.简单介绍3.常见函数4.按钮类型(QMessage::StandardButton)5.分步骤实现弹窗6.总结1.引言

Qt中Qfile类的使用

《Qt中Qfile类的使用》很多应用程序都具备操作文件的能力,包括对文件进行写入和读取,创建和删除文件,本文主要介绍了Qt中Qfile类的使用,具有一定的参考价值,感兴趣的可以了解一下... 目录1.引言2.QFile文件操作3.演示示例3.1实验一3.2实验二【演示 QFile 读写二进制文件的过程】4.

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义

C++如何通过Qt反射机制实现数据类序列化

《C++如何通过Qt反射机制实现数据类序列化》在C++工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作,所以本文就来聊聊C++如何通过Qt反射机制实现数据类序列化吧... 目录设计预期设计思路代码实现使用方法在 C++ 工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作。由于数据类

Qt中QGroupBox控件的实现

《Qt中QGroupBox控件的实现》QGroupBox是Qt框架中一个非常有用的控件,它主要用于组织和管理一组相关的控件,本文主要介绍了Qt中QGroupBox控件的实现,具有一定的参考价值,感兴趣... 目录引言一、基本属性二、常用方法2.1 构造函数 2.2 设置标题2.3 设置复选框模式2.4 是否

QT进行CSV文件初始化与读写操作

《QT进行CSV文件初始化与读写操作》这篇文章主要为大家详细介绍了在QT环境中如何进行CSV文件的初始化、写入和读取操作,本文为大家整理了相关的操作的多种方法,希望对大家有所帮助... 目录前言一、CSV文件初始化二、CSV写入三、CSV读取四、QT 逐行读取csv文件五、Qt如何将数据保存成CSV文件前言

Qt中QUndoView控件的具体使用

《Qt中QUndoView控件的具体使用》QUndoView是Qt框架中用于可视化显示QUndoStack内容的控件,本文主要介绍了Qt中QUndoView控件的具体使用,具有一定的参考价值,感兴趣的... 目录引言一、QUndoView 的用途二、工作原理三、 如何与 QUnDOStack 配合使用四、自

Qt spdlog日志模块的使用详解

《Qtspdlog日志模块的使用详解》在Qt应用程序开发中,良好的日志系统至关重要,本文将介绍如何使用spdlog1.5.0创建满足以下要求的日志系统,感兴趣的朋友一起看看吧... 目录版本摘要例子logmanager.cpp文件main.cpp文件版本spdlog版本:1.5.0采用1.5.0版本主要

Qt 中 isHidden 和 isVisible 的区别与使用小结

《Qt中isHidden和isVisible的区别与使用小结》Qt中的isHidden()和isVisible()方法都用于查询组件显示或隐藏状态,然而,它们有很大的区别,了解它们对于正确操... 目录1. 基础概念2. 区别清见3. 实际案例4. 注意事项5. 总结1. 基础概念Qt 中的 isHidd