```cpp
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QtDebug>
#include <QKeyEvent>
#include <QTimer>
#include <QRectF>
#include <QPointF>
#include <QIcon>
#include <QPainter>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
// 蛇方向
typedef enum direct {
dir_UP,
dir_DOWN,
dir_LEFT,
dir_RIGHT
}dir_t;
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
void topAddRect();
void deleteLast();
void downAddRect();
void leftAddRect();
void rightAddRect();
void addFood();
bool checkHit();
protected:
// 按键按压处理
void keyPressEvent(QKeyEvent *event);
void paintEvent(QPaintEvent *event);
private Q_SLOTS:
void my_timeout();
private:
Ui::Widget *ui;
int moveFlag = dir_t::dir_UP;
bool gameStart = false;
QTimer *timer;
const int startTime = 100;
// 贪吃蛇
QList<QRectF>snakeList;
// 贪吃蛇小方块
const int nodeWidth = 20;
const int nodeHeight = 20;
// 食物
QRectF food;
};
#endif // WIDGET_H
```
```cpp
#include "widget.h"
#include "ui_widget.h"
// 三个方块代码蛇,最上面的第一个和最后面的一个通过按键进行交替删除 即snake[0]永远表示头
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
this->setWindowTitle("贪吃蛇疯子");
this->setWindowIcon(QIcon(":/icons/title.jpg"));
qDebug()<<"x = "<<this->x()<<" y = "<<this->y()<<" height = "<<this->height()<<" width = "<<this->width();
timer = new QTimer();
connect(timer, &QTimer::timeout, this , &Widget::my_timeout);
// 初始化蛇身子 3个方块
QRectF rect(this->width()/2,this->height()/2,nodeWidth,nodeHeight);
snakeList.append(rect);
topAddRect();
topAddRect();
// 添加食物
addFood();
}
Widget::~Widget()
{
delete ui;
}
// 增加一个方块 左上和右下确认一个方块坐标系
void Widget::topAddRect()
{
QPointF leftTop; // 左上角坐标
QPointF rightBottom; // 右上角坐标
if (snakeList[0].y() <= 0) {
// 当蛇移动到窗口顶部:确认新坐标 y = 窗口高度 - 蛇方块高度
leftTop = QPointF(snakeList[0].x(), this->height() - nodeHeight);
rightBottom = QPointF(snakeList[0].x() + nodeWidth , this->height());
}
else {
// 向上移动:y坐标必然减少 减少的右下角坐标为之前的下一个方块的右上角坐标
leftTop = QPointF(snakeList[0].x(), snakeList[0].y() - nodeHeight);
rightBottom = snakeList[0].topRight();
}
// 插入矩形小方块1个,由于采用的是List链表,这是典型的前插,追加
snakeList.insert(0,QRectF(leftTop,rightBottom));
}
void Widget::downAddRect()
{
QPointF leftTop; // 左上角坐标
QPointF rightBottom; // 右上角坐标
if (snakeList[0].y() > this->height() - nodeHeight) {
// 当蛇移动到窗口底部:确认新坐标 y = 0
leftTop = QPointF(snakeList[0].x(), 0);
rightBottom = QPointF(snakeList[0].x() + nodeWidth, 0 + nodeHeight);
}
else {
// 向下移动:y坐标必然增加
leftTop = QPointF(snakeList[0].x(), snakeList[0].y() + nodeHeight);
rightBottom = snakeList[0].bottomRight() + QPointF(0,nodeHeight);
}
// 插入矩形小方块1个
snakeList.insert(0,QRectF(leftTop,rightBottom));
}
void Widget::leftAddRect()
{
QPointF leftTop; // 左上角坐标
QPointF rightBottom; // 右上角坐标
if (snakeList[0].x() <= 0) {
// 当蛇移动到窗口最左部:确认新坐标 x = 窗口宽度 - 小方块宽度
leftTop = QPointF(this->width() - nodeWidth, snakeList[0].y());
}
else {
// 向左移动:x坐标必然减少
leftTop = QPointF(snakeList[0].x() - nodeWidth, snakeList[0].y());
}
// 右下角坐标 = 之前一个的左上角坐标x,y + 小方块的宽高
rightBottom = leftTop + QPointF(nodeWidth, nodeHeight);
// 插入矩形小方块1个
snakeList.insert(0,QRectF(leftTop,rightBottom));
}
void Widget::rightAddRect()
{
QPointF leftTop; // 左上角坐标
QPointF rightBottom; // 右上角坐标
if (snakeList[0].x() + nodeWidth > this->width()) {
// 当蛇移动到窗口最右部:确认新坐标 x = 0
leftTop = QPointF(0, snakeList[0].y());
}
else {
// 向右移动:x坐标必然增加
leftTop = QPointF(snakeList[0].x() + nodeWidth, snakeList[0].y());
}
// 右下角坐标 = 之前一个的左上角坐标x,y + 小方块的宽高
rightBottom = leftTop + QPointF(nodeWidth, nodeHeight);
// 插入矩形小方块1个
snakeList.insert(0,QRectF(leftTop,rightBottom));
}
// 删除蛇身最后一个
void Widget::deleteLast()
{
snakeList.removeLast();
}
// 食物是随机出现的
void Widget::addFood()
{
int rectX = (qrand() % (this->width() / 20)) * 20;
int rectY = (qrand() % (this->height() / 20)) * 20;
// 控制小球出现的范围
if (rectX >= 0 && rectY>=0) {
food = QRectF(rectX, rectY, nodeWidth, nodeHeight);
qDebug()<<"food = "<<food;
}
}
// 蛇头和蛇身碰撞检查,其实就是蛇头和蛇尾其中一个方块重合
bool Widget::checkHit()
{
// 整个蛇的长度都遍历一遍
for (int i =0 ; i < snakeList.length(); i++) {
// 从蛇头后的第一个开始检查 只要有
for (int j= i+ 1; j < snakeList.length();j++) {
// rect0和rectx相等,表示它们的坐标、宽度和高度都一致
if (snakeList[0] == snakeList[j]) {
return true;
}
}
}
return false;
}
void Widget::keyPressEvent(QKeyEvent *event)
{
switch (event->key()) {
case Qt::Key::Key_Up:
if (moveFlag != dir_DOWN) {
moveFlag = dir_UP;
}
break;
case Qt::Key::Key_Down:
if (moveFlag != dir_UP) {
moveFlag = dir_DOWN ;
}
break;
case Qt::Key::Key_Left:
if (moveFlag != dir_RIGHT) {
moveFlag = dir_LEFT;
}
break;
case Qt::Key::Key_Right:
if (moveFlag != dir_LEFT) {
moveFlag = dir_RIGHT;
}
break;
case Qt::Key_Space:
if (gameStart == false) {
gameStart = true;
timer->start(startTime); // 100ms
}
else {
gameStart = false;
timer->stop();
}
break;
default:
break;
}
}
void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
QPen pen;
QBrush brush;
QPixmap pix;
// 绘制图片背景
pix.load(":/icons/bg_snake.png");
painter.drawPixmap(0,0,this->width(),this->height(),pix);
// 绘制蛇
pen.setColor(Qt::color0);
brush.setColor(Qt::darkGreen); // 绿色
brush.setStyle(Qt::SolidPattern); // 实线图案
painter.setPen(pen);
painter.setBrush(brush);
for (int i = 0; i < snakeList.length(); i++) {
painter.drawRect(snakeList[i]);
}
// 分数
ui->label_score->setText(QString::number(snakeList.length() -3));
// 绘制食物
painter.drawEllipse(food);
// 蛇头碰到蛇身结束游戏
if (checkHit()) {
QFont font("方正舒体",30,QFont::ExtraLight,false);
painter.setFont(font);
painter.drawText((this->width() - 200)/2,this->height()/2,QString("游戏结束"));
timer->stop();
}
QWidget::paintEvent(event);
}
// 定时器槽函数
void Widget::my_timeout()
{
//int count = 1; // 采用这种方式也可以加长蛇身,不过我还是喜欢我的烂方法
// 判断蛇是否吃到食物 是否重合[交叉;相交;贯穿;横穿;横断] 蛇变长
if (snakeList[0].intersects(food)) {
qDebug()<<"吃到食物 snakeList[0] = "<<snakeList[0]<<" food = "<<food;
//count ++ ; // 例如 2
switch (moveFlag) {
case dir_UP:
this->topAddRect(); // +1
break;
case dir_DOWN:
this->downAddRect(); // +1
break;
case dir_LEFT:
this->leftAddRect(); // +1
break;
case dir_RIGHT:
this->rightAddRect(); // +1
break;
default:
break;
}
addFood(); // 食物位置变化
return;
}
// 加长蛇身 每次在最前面增加一个
// while (count--) {
switch (moveFlag) {
case dir_UP:
this->topAddRect(); // +1
break;
case dir_DOWN:
this->downAddRect(); // +1
break;
case dir_LEFT:
this->leftAddRect(); // +1
break;
case dir_RIGHT:
this->rightAddRect(); // +1
break;
default:
break;
}
//}
// 为了动态显示每次最前面插入一个,最后面就减少一个
deleteLast(); // 删除蛇尾 -1
this->update(); // 刷新绘制函数
}
```
QTimer是Qt中用于定时器操作的类,它提供了一些常用的函数来控制和管理定时器的运行。下面是一些常用的QTimer函数的简介:
这些函数提供了基本的定时器操作功能,可以配合定时器的信号timeout()以及连接(Qt的信号与槽机制)来实现所需的定时操作。
QKeyEvent是Qt中用于处理键盘事件的类,它提供了一些常用的函数来获取和处理键盘事件的相关信息。下面是一些常用的QKeyEvent函数的简介:
这些函数可以帮助你获取与键盘事件相关的信息,例如获取按下的键是哪个键,是否同时按下了修饰键,以及自动重复事件的次数等。你可以使用这些函数来处理键盘事件并根据需要执行相应的操作。
QRectF是Qt中用于表示浮点数精度的矩形区域的类,它提供了一些常用的函数来操作和管理矩形区域。下面是一些常用的QRectF函数的简介:
QPointF是Qt中用于表示浮点数精度的二维点的类,它提供了一些常用的函数来操作和管理点的坐标。下面是一些常用的QPointF函数的简介:
这些函数提供了对点的基本操作,包括设置坐标、获取坐标、判断点是否为空、计算与其他点或直线的距离等。你可以使用这些函数来创建、修改和计算点的坐标,以满足你的需求。
QPainter是Qt提供的一个用于绘图的类,它封装了绘制图形、图像以及文本的功能。下面是一些常用的QPainter函数的简介:
这些函数提供了绘制基本图形、文本和图像的能力,通过设置画笔、刷子和渲染提示等属性,可以实现不同样式的绘制效果。同时,你还可以使用平移、缩放和旋转等变换函数来改变画笔的绘制位置和方向。使用这些函数,你可以实现各种绘图需求,创建出丰富多样的用户界面。
QIcon是Qt提供的一个用于管理图标的类,它可以加载、显示和操作图标。下面是一些常用的QIcon函数的简介:
这些函数提供了加载、显示和操作图标的功能,你可以根据需要加载图像文件,设置图标的大小、模式和状态,绘制图标到指定的区域,并进行图标的比较和赋值操作。QIcon类在Qt中广泛用于界面开发,它使得图标的管理和使用变得简单和
粉丝福利,莬费领取Qt开发学习资料包、技术视频,内容包括(Qt实战项目视频教程+代码,C++语言基础,C++设计模式,Qt编程入门,Qt信号与槽机制,Qt界面开发-图像绘制,Qt网络,Qt数据库编程,Qt项目实战教程,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击莬费领取↓↓
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- bangwoyixia.com 版权所有 湘ICP备2023022004号-2
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务