Qt—贪吃蛇项目(由0到1实现贪吃蛇项目)
用Qt实现一个贪吃蛇项目
- 一、项目介绍
- 二、游戏大厅界面实现
- 2.1完成游戏大厅的背景图。
- 2.2创建一个按钮,给它设置样式,并且可以跳转到别的页面
- 三、难度选择界面实现
- 四、 游戏界面实现
- 五、在文件中写入历史战绩
- 5.1 从文件里提取分数
- 5.2 把贪吃蛇的长度存入文件
- 六、总结
一、项目介绍
贪吃蛇是久负盛名的游戏,它也和俄罗斯⽅块,扫雷等游戏位列经典游戏的⾏列。 在编程语⾔的教学中,我们以贪吃蛇为例,从设计到代码实现来提升编程能⼒和逻辑能⼒。它通过控制蛇头⽅向吃⻝物,从⽽使得蛇变得越来越⻓。在本游戏中设置了上下左右四个⽅向键来控制蛇的移动⽅向。⻝物的产⽣是随机⽣成的,当蛇每吃⼀次⻝物 就会增加⼀节⾝体,同时游戏积分也会相应的加⼀。
在本游戏的设计中,蛇的⾝体会越吃越⻓,⾝体越⻓对应的难度就越⼤,因为⼀旦蛇头和⾝体相交游戏就会结束。
本项⽬使⽤ Qt 实现⼀款简单的贪吃蛇游戏。
项目的目标:
- 游戏大厅界面实现
- 难度选择界面实现
- 游戏界面实现
- 分数记录界面实现
二、游戏大厅界面实现
2.1完成游戏大厅的背景图。
1.背景图的渲染,我们通过QT的绘图事件完成
void gamehall::paintEvent(QPaintEvent *event)
{//实例化一个画家QPainter paint(this);//实例化一个设备QPixmap pix(":res/game_hall.png");//进行绘画paint.drawPixmap(0,0,this->width(),this->height(),pix);}
2.对我们的标题栏进行设置
//设置窗口大小this->setFixedSize(1000,800);//设置标题栏图标this->setWindowIcon(QIcon(":res/ico.png"));//设置标题栏标签this->setWindowTitle("游戏大厅");
2.2创建一个按钮,给它设置样式,并且可以跳转到别的页面
1.创建一个按钮,给它设置样式
QFont font("华文行楷",25);//设置按钮QPushButton *intoBtn= new QPushButton(this);intoBtn->setFont(font);intoBtn->setText("开始游戏");intoBtn->setStyleSheet("QPushButton{border:0px;}");intoBtn->move(450,520);
2.创建的新页面
点击add new
3. 建立信号槽,使按钮被点击后跳转界面(这个跳转的界面,是新创建的文件,点击按钮会发出声音)
//创建另一个窗口GameSelect *select=new GameSelect();connect(intoBtn,&QPushButton::clicked,[=]{//关闭上个窗口this->close();//设置窗口大小select->setGeometry(this->geometry());//显示窗口select->show();//发出声音QSound::play(":res/clicked.wav");
4.总代码
#include "gamesnake.h"
#include "ui_gamesnake.h"
#include "gameselect.h"
#include <QPainter>
#include <QPixmap>
#include <QIcon>
#include <QPushButton>
#include <QSound>
GameSnake::GameSnake(QWidget *parent): QWidget(parent), ui(new Ui::GameSnake)
{ui->setupUi(this);//设置窗口大小this->setFixedSize(1000,800);//设置窗口图标this->setWindowIcon(QIcon(":res/ico.png"));//设置窗口标签this->setWindowTitle("游戏大厅");//设置字体QFont font("华文行楷",25);//设置按钮QPushButton *intoBtn= new QPushButton(this);intoBtn->setFont(font);intoBtn->setText("开始游戏");intoBtn->setStyleSheet("QPushButton{border:0px;}");intoBtn->move(450,520);//创建另一个窗口GameSelect *select=new GameSelect();connect(intoBtn,&QPushButton::clicked,[=]{//关闭上个窗口this->close();select->setGeometry(this->geometry());select->show();QSound::play(":res/clicked.wav");});
}GameSnake::~GameSnake()
{delete ui;
}void GameSnake::paintEvent(QPaintEvent *event)
{//实例化一个画家QPainter paint(this);//实例化一个设备QPixmap pix(":res/game_hall.png");//进行绘画paint.drawPixmap(0,0,this->width(),this->height(),pix);
}
注意pro文件里的配置加上multimedai
三、难度选择界面实现
我们已经把贪吃蛇的游戏界面完成了,下面就进入关卡选择界面。
在关卡选择界⾯上设置了四个游戏模式按钮,分别是:容易模式、正常模式、困难模式、地狱模式;⼀个 “历史战绩” 按钮;⼀个返回游戏⼤厅界⾯的按钮。
1. 创建按钮,给它设置样式。
//容易关卡QPushButton *briefnessBtn= new QPushButton(this);briefnessBtn->setStyleSheet("QPushButton{background-color:#0072C6;color: black; border:0px groove gray;border-radius:10px;padding:6px;}");briefnessBtn->move(400,200);QFont font("华文行楷",25);briefnessBtn->setFont(font);briefnessBtn->setText("容易模式");
如图,我已经创建了5个按钮:
2. 为了使第二个界面可以返回到第一个界面,创建一个按钮,按下按钮触发信号,就可以返回第一个页面。(返回按钮)
//返回按钮
QPushButton *returnBtn= new QPushButton(this);
returnBtn->move(850,700);
returnBtn->setIcon(QIcon(":res/up.png"));connect(returnBtn,&QPushButton::clicked,[=]{this->close();GameSnake *snake= new GameSnake();snake->show();QSound::play(":res/clicked.wav");});
3. 游戏选择页面跳转到游戏大厅
实现页面之间的跳转
//实现游戏房间和选择关卡切换//创建另一个窗口GameRoom *room=new GameRoom();//创建按钮,给按钮设置格式//容易关卡QPushButton *briefnessBtn= new QPushButton(this);briefnessBtn->setStyleSheet("QPushButton{background-color:#0072C6;color: black; border:0px groove gray;border-radius:10px;padding:6px;}");briefnessBtn->move(400,200);QFont font("华文行楷",25);briefnessBtn->setFont(font);briefnessBtn->setText("容易模式");connect(briefnessBtn,&QPushButton::clicked,[=]{//关闭上个窗口this->close();room->setGeometry(this->geometry());room->show();QSound::play(":res/clicked.wav");});
以第一个按钮为例,运行后点击简单模式效果如下(这是一个新的界面):
4. 总代码
#include "gameselect.h"
#include <QPainter>
#include <QPixmap>
#include <QPushButton>
#include "gamesnake.h"#
#include "gameroom.h"
#include <QSound>
GameSelect::GameSelect(QWidget *parent) : QWidget(parent)
{this->setFixedSize(1000,800);//设置窗口图标this->setWindowIcon(QIcon(":res/ico.png"));//设置窗口标签this->setWindowTitle("选择大厅");//实现游戏房间和选择关卡切换//创建另一个窗口GameRoom *room=new GameRoom();//创建按钮,给按钮设置格式//容易关卡QPushButton *briefnessBtn= new QPushButton(this);briefnessBtn->setStyleSheet("QPushButton{background-color:#0072C6;color: black; border:0px groove gray;border-radius:10px;padding:6px;}");briefnessBtn->move(400,200);QFont font("华文行楷",25);briefnessBtn->setFont(font);briefnessBtn->setText("容易模式");connect(briefnessBtn,&QPushButton::clicked,[=]{//关闭上个窗口this->close();room->setGeometry(this->geometry());room->show();QSound::play(":res/clicked.wav");});//正常关卡QPushButton *normalBtn= new QPushButton(this);normalBtn->setStyleSheet("QPushButton{background-color:#0072C6;color: black; border:0px groove gray;border-radius:10px;padding:6px;}");normalBtn->move(400,280);QFont font1("华文行楷",25);normalBtn->setFont(font);normalBtn->setText("正常模式");connect(normalBtn,&QPushButton::clicked,[=]{//关闭上个窗口this->close();room->setGeometry(this->geometry());room->show();QSound::play(":res/clicked.wav");});//困难关卡QPushButton *difficultyBtn= new QPushButton(this);difficultyBtn->setStyleSheet("QPushButton{background-color:#0072C6;color: black; border:0px groove gray;border-radius:10px;padding:6px;}");difficultyBtn->move(400,360);QFont font2("华文行楷",25);difficultyBtn->setFont(font);difficultyBtn->setText("困难模式");connect(difficultyBtn,&QPushButton::clicked,[=]{//关闭上个窗口this->close();room->setGeometry(this->geometry());room->show();QSound::play(":res/clicked.wav");});//地狱关卡
QPushButton *bhellBtn= new QPushButton(this);
bhellBtn->setStyleSheet("QPushButton{background-color:#0072C6;color: black; border:0px groove gray;border-radius:10px;padding:6px;}");
bhellBtn->move(400,440);
QFont font3("华文行楷",25);
bhellBtn->setFont(font);
bhellBtn->setText("地狱模式");
connect(bhellBtn,&QPushButton::clicked,[=]{//关闭上个窗口this->close();room->setGeometry(this->geometry());room->show();QSound::play(":res/clicked.wav");});//排行榜
QPushButton *ranpingBtn= new QPushButton(this);
ranpingBtn->setStyleSheet("QPushButton{background-color:#0072C6;color: black; border:0px groove gray;border-radius:10px;padding:6px;}");
ranpingBtn->move(400,520);
QFont font4("华文行楷",25);
ranpingBtn->setFont(font);
ranpingBtn->setText("历史战绩");//返回按钮
QPushButton *returnBtn= new QPushButton(this);
returnBtn->move(850,700);
returnBtn->setIcon(QIcon(":res/up.png"));connect(returnBtn,&QPushButton::clicked,[=]{this->close();GameSnake *snake= new GameSnake();snake->show();QSound::play(":res/clicked.wav");});
}
void GameSelect::paintEvent(QPaintEvent *event)
{//设置窗口大小this->setFixedSize(1000,800);//创建绘画者QPainter paint(this);//创建画板QPixmap pix(":res/game_select.png");paint.drawPixmap(0,0,this->width(),this->height(),pix);
}
注意:历史战绩还没有设计
四、 游戏界面实现
前两个页面已经实现完成了,最后完成游戏界面,我们就可以玩上自己写的游戏了。
游戏房间界⾯包含下⾯⼏个部分:
• 背景图的绘制。
• 蛇的绘制、蛇的移动、判断蛇是否会撞到⾃⼰ 。
• 积分的累加和绘制 在这⾥我们要考虑⼏个⽐较核⼼的问题:
- 怎么让蛇动起来?
• 我们可以⽤⼀个链表表⽰贪吃蛇,⼀个⼩⽅块表⽰蛇的⼀个节点, 我们设置蛇的默认⻓度为3。
• 向上移动的逻辑就是在蛇的上⽅加⼊⼀个⼩⽅块, 然后把最后⼀个⼩⽅块删除即可。
• 需要⽤到定时器Qtimer 每100 - 200ms 重新渲染。- 怎么判断蛇有没有吃到⻝物?
• 判断蛇头和⻝物的坐标是否相交,Qt 有相关的接⼝调⽤。- 怎么控制蛇的移动?
• 借助QT的实践机制实现, 重写keyPressEvent即可, 在函数中监控想要的键盘事件即可 。
• 我们通过绘制四个按钮,使⽤信号和槽的机制控制蛇的上、下、左、右移动⽅向。
1.先要对游戏界面进行渲染,用到pixmap和painter。
void GameRoom::paintEvent(QPaintEvent *event)
{qDebug("开始绘画");//创建绘画者QPainter paint(this);//创建画板,不带有参数QPixmap pix;//load方法,加载资源或者数据//游戏区域pix.load(":res/game_room.png");paint.drawPixmap(0,0,800,800,pix);//控制区域pix.load(":res/bg1.png");paint.drawPixmap(800,0,201,900,pix);
}
2.创建一个按钮,实现页面之间的跳转
//创建一个返回按钮QPushButton* returnButton = new QPushButton(this);//设置位置和按钮照片returnButton->move(900,700);returnButton->setIcon(QIcon(":res/up.png"));//创建信号槽connect(returnButton,&QPushButton::clicked,[=]{//关闭当前页面this->close();GameSelect *gameRn = new GameSelect();//显示上个页面gameRn->show();QSound::play(":res/clicked.wav");});
如图:
3. 对游戏房间数据结构进行封装
gameroom的头文件
#define GAMEROOM_H#include <QWidget>
//枚举蛇的移动方向
enum class kSnakeDirect
{UP = 0,DOWN,LEFT,RIGHT
};class GameRoom : public QWidget
{Q_OBJECT
public:explicit GameRoom(QWidget *parent = nullptr);//重写绘画事件void paintEvent(QPaintEvent *event);
private://表示蛇身体结点的宽度const int kSnakeNodeWidth = 20;//表示蛇身体节点的高度const int kSnakeNodeHeight = 20;//表示蛇的速度const int KDefountTimeout = 100;//表示贪吃蛇的链表QList<QRectF> snakeList;//表示食物的结点QRectF foodRect;//表示蛇初始方向的默认值kSnakeDirect moveDirect = kSnakeDirect::UP;
};
4.蛇移动方向的实现
注意: 这⾥贪吃蛇不允许直接掉头, ⽐如当前是向上的, 不能直接修改为向下。
分别声明:
void moveUp();//蛇向上移动
void moveDown();//蛇向下移动
void moveLeft();//蛇向左移动
void moveRight();//蛇向右移动
列如蛇向上移动的定义
void GameRoom::moveUp()
{QPointF leftTop; // 左上⻆坐标QPointF rightBottom; // 右下⻆坐标auto snakeNode = snakeList.front();int headX = snakeNode.x();int headY = snakeNode.y();// 如果上⾯剩余的空间不够放⼊⼀个新的节点, 相当于到墙边了, 要处理穿墙逻辑if(headY-kSnakeNodeWidth < 0) {leftTop = QPointF(headX, this->height() - kSnakeNodeHeight);} else {leftTop = QPointF(headX, headY - kSnakeNodeHeight);}rightBottom = leftTop + QPointF(kSnakeNodeWidth, kSnakeNodeHeight);snakeList.push_front(QRectF(leftTop, rightBottom));
}
5.判断游戏是否结束
贪吃蛇游戏的结束标志是自己碰到自己,才算结束。
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;//游戏正常运行
}
6.在绘图事件里把蛇绘画出来,并初始化贪吃蛇
//绘制蛇:蛇头+蛇身+蛇尾//绘制蛇头的上下左右if(moveDirect==kSnakeDirect::UP){pix.load(":res/rescopy.png");//加载资源}else if(moveDirect == kSnakeDirect::DOWN){pix.load(":res/rescopy1.png");//加载资源}else if(moveDirect==kSnakeDirect::LEFT){pix.load(":res/rescopy 2.png");//加载资源}else{pix.load(":res/rescopy3.png");//加载资源}//获取链表的头结点auto snakeHeadNode=snakeList.front();//画家绘画,给这个结点绘制pix里面的资源paint.drawPixmap(snakeHeadNode.x(),snakeHeadNode.y(),snakeHeadNode.width(),snakeHeadNode.height(),pix);//绘制蛇身pix.load(":res/rescopy 5.png");for(int i=1;i<snakeList.size()-1;i++){auto node=snakeList.at(i);paint.drawPixmap(node.x()+2,node.y(),node.width()-3,node.height(),pix);}//绘制蛇尾auto TailNode = snakeList.back();paint.drawPixmap(TailNode.x()+2,TailNode.y(),TailNode.width()-3,TailNode.height(),pix);
在构造函数里,初始化贪吃蛇
// 初始化贪吃蛇snakeList.push_back(QRectF(this->width() * 0.5, this->height() * 0.5,kSnakeNodeWidth, kSnakeNodeHeight));moveUp();moveUp();
7. 定义贪吃蛇的食物
//创建随机的食物
void GameRoom::creatNewFood()
{foodRect= QRectF(qrand()%(800/kSnakeNodeWidth)*kSnakeNodeWidth,qrand()%(800/kSnakeNodeHeight)*kSnakeNodeHeight,kSnakeNodeWidth,kSnakeNodeHeight);
}
//在绘图事件里,绘制食物//绘制食物pix.load(":res/food.bmp");paint.drawPixmap(foodRect.x(),foodRect.y(),foodRect.width(),foodRect.height(),pix);
8.让贪吃蛇移动起来
定时器的是为了实现每隔⼀段时间能处理移动的逻辑并且更新绘图事件。
• ⾸先, 需要判断蛇头和⻝物节点坐标是否相交 ◦ 如果相交, 需要创建新的⻝物节点, 并且需要更新蛇的⻓度, 所以 cnt 需要 +1 ;
• 如果不相交, 那么直接处理蛇的移动即可。
• 根据蛇移动⽅向 moveDirect 来处理蛇的移动, 处理⽅法是在前⽅加⼀个, 并且删除后⽅节点;
• 重新触发绘图事件, 更新渲染。
//在构造函数里编写
timer = new QTimer(this);connect(timer, &QTimer::timeout, this, [=](){int cnt = 1;// 判断是否贪吃蛇和⻝物是否相交if (snakeList.front().intersects(foodRect)) {createNewFood();++cnt;//蛇吃食物的声音QSound::play(":res/eatfood.wav");}while(cnt--) {// 处理蛇的移动switch (moveDirect) {case SnakeDirect::UP:moveUp();break;case SnakeDirect::DOWN:moveDown();break;case SnakeDirect::LEFT:moveLeft();break;case SnakeDirect::RIGHT:moveRight();break;default:qDebug() << "⾮法移动⽅向";break;}}// 删除最后⼀个节点snakeList.pop_back();update();});
9.设置游戏开始和游戏暂停按钮
在刚进⼊游戏房间界⾯时,⼀定不能点击 “退出” 按钮,如果点击 “退出” 按钮,那么程 序就会异常退出。点击的顺序⼀定是:先点击 “开始” 按钮,最后才能点击 “退出” 。
//设置开始暂停按钮QPushButton *startbtn = new QPushButton(this);QPushButton *stopbtn = new QPushButton(this);QFont ft("楷体", 20);//设置按钮的位置startbtn->move(860,150);stopbtn->move(860,200);//设置按钮⽂本startbtn->setText("开始");stopbtn->setText("暂停");//设置按钮样式startbtn->setStyleSheet("QPushButton{border:0px;}");stopbtn->setStyleSheet("QPushButton{border:0px;}");//设置按钮字体格式startbtn->setFont(ft);stopbtn->setFont(ft);//蛇移动connect(startbtn,&QPushButton::clicked,this,[=](){isGameStart = true;timer->start(kDefountTimeout);sound = new QSound(":res/Trepak.wav"); //声⾳路径sound->play(); //播放sound->setLoops(-1); //循环播放});//蛇暂停connect(stopbtn,&QPushButton::clicked,this,[=](){isGameStart = false;timer->stop();//停止工作sound->stop();//停止播放});
10. 设置蛇的方向控制
//设置蛇2的移动方向QPushButton *Up = new QPushButton(this);QPushButton *Down = new QPushButton(this);QPushButton *Left = new QPushButton(this);QPushButton *Right = new QPushButton(this);Up->move(880,400);Down->move(880,480);Left->move(840,440);Right->move(920,440);Up->setStyleSheet("QPushButton{border:0px;}");Up->setFont(font);Up->setText("↑");Down->setStyleSheet("QPushButton{border:0px;}");Down->setFont(font);Down->setText("↓");Left->setStyleSheet("QPushButton{border:0px;}");Left->setFont(font);Left->setText("←");Right->setStyleSheet("QPushButton{border:0px;}");Right->setFont(font);Right->setText("→");connect(Up,&QPushButton::clicked,this,[=](){if(moveDirect != kSnakeDirect::DOWN)moveDirect = kSnakeDirect::UP;});connect(Down,&QPushButton::clicked,this,[=](){if(moveDirect != kSnakeDirect::UP)moveDirect = kSnakeDirect::DOWN;});connect(Left,&QPushButton::clicked,this,[=](){if(moveDirect != kSnakeDirect::RIGHT)moveDirect = kSnakeDirect::LEFT;});connect(Right,&QPushButton::clicked,this,[=](){if(moveDirect != kSnakeDirect::LEFT)moveDirect = kSnakeDirect::RIGHT;});
我们也可以用键盘来控制蛇的方向
void GameRoom::keyPressEvent(QKeyEvent *event)
{switch (event->key()) {case Qt::Key_W :case Qt::Key_Up :if(moveDirect != kSnakeDirect::DOWN)moveDirect = kSnakeDirect::UP;break;case Qt::Key_S :case Qt::Key_Down :if(moveDirect != kSnakeDirect::UP)moveDirect=kSnakeDirect::DOWN;break;case Qt::Key_D :case Qt::Key_Right :if(moveDirect != kSnakeDirect::LEFT)moveDirect=kSnakeDirect::RIGHT;break;case Qt::Key_A :case Qt::Key_Left :if(moveDirect != kSnakeDirect::RIGHT)moveDirect=kSnakeDirect::LEFT;break;//开始case Qt::Key_F :isGameStart = true;timer->start(moveDefount);sound = new QSound(":res/Trepak.wav"); //声⾳路S径sound->play(); //播放sound->setLoops(-1); //循环播放break;
// //暂停case Qt::Key_G :isGameStart = false;timer->stop();//停止工作sound->stop();//停止播放break;}
}
11.设置游戏退出按钮,并设置一个消息盒子。
//设置退出按钮,并给他设置样式QPushButton *exitBtn=new QPushButton(this);exitBtn->setText("退出");exitBtn->move(870,750);exitBtn->setFont(font);//设置消息盒子QMessageBox *msg=new QMessageBox(this);QPushButton *okBtn =new QPushButton("OK");QPushButton *cancelBtn =new QPushButton("cancel");msg->addButton(okBtn,QMessageBox::AcceptRole);msg->addButton(cancelBtn,QMessageBox::RejectRole);msg->setWindowTitle("退出游戏");msg->setText("确认退出游戏吗?");connect(exitBtn,&QPushButton::clicked,[=]{//显示消息盒子msg->show();QSound::play(":res/clicked.wav");//事件轮询msg->exec();if(msg->clickedButton()==okBtn){this->close();//关闭程序}else{msg->close();//关闭信息盒子}});
12. 分数的绘制
//绘制分数pix.load(":res/sorce_bg.png");paint.drawPixmap(this->width()*0.85,this->height()*0.06,90,40,pix);QPen pen;pen.setColor(Qt::black);QFont font("方正舒体",22);paint.setPen(pen);paint.setFont(font);paint.drawText(this->width()*0.9,this->height()*0.1,QString("%1").arg(snakeList.size()));
13.游戏失败的绘制
//绘制游戏失败效果if(checkFail()){pen.setColor(Qt::red);paint.setPen(pen);QFont font("方正舒体",50);paint.setFont(font);paint.drawText(this->width()*0.25,this->height()*0.5,QString("GAME OVER!"));timer->stop();QSound::play((":res/gameover.wav"));sound->stop();}
14.实现4种不同游戏模式
先对各个模式的时间进行设置,然后设置房间的定时器时间,从而改变游戏的模式。
room->setTimer(200);//改变各个模式的速度默认值
通过默认值去改变时间,从而设置游戏模式
五、在文件中写入历史战绩
通过文件的方式用来显示历史战绩
5.1 从文件里提取分数
读⽂件:读取写⼊⽂件中蛇的⻓度
connect(ranpingBtn,&QPushButton::clicked,[=]{//创建一个窗口控件QWidget *wGet=new QWidget();wGet->setWindowTitle("历史战绩");wGet->setFixedSize(500,300);//创建一个多行输入框QTextEdit *edit=new QTextEdit(wGet);edit->setFont(font);edit->setFixedSize(500,300);//打开文件,并且只能读,文件要自己创建QFile file("D:/QT_creator_3_25/greedy_snake1/Snake/res/1.txt");file.open(QIODevice::ReadOnly);//文本流对象QTextStream in(&file);//in.表示文件,把文件里的数据按行读取,并且转化为整数int data=in.readLine().toInt();edit->append("得分为:");//这里需要的是QString类型,把整形转化为字符串edit->append(QString::number(data));//显示窗口wGet->show();QSound::play(":res/clicked.wav");file.close();
});
5.2 把贪吃蛇的长度存入文件
写⽂件:往⽂件中写⼊蛇的⻓度
//把分数存入文件int c=snakeList.size();QFile file("D:/QT_creator_3_25/greedy_snake1/Snake/res/1.txt");if(file.open(QIODevice::Text|QIODevice::WriteOnly)){//输入文本和只写QTextStream out(&file);out<<c;//关闭文件file.close();}
最后通过黑盒测试的方法,解决程序的一些问题,确保程序正常运行。(解决了按左右键,游戏就失败的问题;解决了蛇不在窗口跑的问题)
六、总结
做完这个项目,收获非常大。对qt代码的理解也更加深刻,同时也了解了一点额外的知识点
注意:
- QPixmap中的load函数是将图片加载到缓冲区,即QPixmapCache中存放图片,当把第一张图片加载到缓冲区会显示图片1,当加载第二张图片时缓冲区的图片1并没有被覆盖,实际是缓冲区存了两张图片,并显示图片2,当再次加载图片1到缓冲区时,这时QPixmapCache认为已经有了图片1,会直接返回true,缓冲区的图片排列顺序并没有发生变化,固依旧显示图片2。
解决办法:
(1)QPixmap直接定义局部变量,这样每次会开辟新的缓冲区
(2)每次加载图片时先清空缓冲区,调用QPixmapCache::clear()- QPointF就是Float QPoint,用法的话QPointF在浮点精度上表示平面上的点,绝大部分操作都是与QPoint相类似的,细微的差别在于运算符重载以及提供了QPoint与QPointF的相互转换。
- 在Qt中QList和QVector一般获取元素都是通过 at(index) 来获取得,但是at获取的元素返回值是一个const & 常引用,也就是元素不支持改变。
- snakeList.front().intersects(foodRect),判断两个矩形会不会相交。
- QTextStream文本流对象
QTextStream out(&文件指针)
QTextStream in(&文件指针)
相关文章:
Qt—贪吃蛇项目(由0到1实现贪吃蛇项目)
用Qt实现一个贪吃蛇项目 一、项目介绍二、游戏大厅界面实现2.1完成游戏大厅的背景图。2.2创建一个按钮,给它设置样式,并且可以跳转到别的页面 三、难度选择界面实现四、 游戏界面实现五、在文件中写入历史战绩5.1 从文件里提取分数5.2 把贪吃蛇的长度存入…...
Java导出Excel并邮件发送
一、导出Excel 添加maven依赖 <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.10-FINAL</version></dependency><dependency><groupId>org.apache.poi</groupI…...
【课程总结】Day12:YOLO的深入了解
前言 在【课程总结】Day11(下):YOLO的入门使用一节中,我们已经了解YOLO的使用方法,使用过程非常简单,训练时只需要三行代码:引入YOLO,构建模型,训练模型;预测…...
保护隐私,释放智能:使用LangChain和Presidio构建安全的AI问答系统
保护隐私,释放智能:使用LangChain和Presidio构建安全的AI问答系统 在人工智能(AI)飞速发展的今天,AI问答系统已经成为企业与客户互动的重要工具。然而,随之而来的个人数据隐私问题也日益凸显。如何在不泄露…...
【高考志愿】自动化
目录 一、专业概述 二、课程设计 三、就业前景与方向 四、志愿填报 五、自动化专业排名 一、专业概述 高考志愿自动化专业选择,无疑是迈向现代化工业与科技发展的一把金钥匙。自动化专业,作为现代工程领域的重要支柱,融合了计算机、电子…...
技巧类题目
目录 技巧类题目 136 只出现一次的数字 191 位1的个数 231. 2 的幂 169 多数元素 75 颜色分类 (双指针) 287. 寻找重复数 136 只出现一次的数字 给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均…...
Vue3自定义指令参数修饰符值(3)
自定义指令参数修饰符值 在vue3中我们如何获取自定义的参数的内容,并根据业务来修改展示的内容呢,需要依靠mounted方法中的bindings参数来获取。 参考实例 directives/unit.js文件 export default function directiveUnit(app){app.directive("unit",{…...
HTML(23)——垂直对齐方式
垂直对齐方式 属性名:vertical-align 属性值效果baseline基线对齐(默认)top顶部对齐middle居中对齐bottom底部对齐 默认情况下浏览器对行内块,行内标签都按文字处理,默认基线对齐 导致图片看起来会偏上,文字偏下。 示例&#…...
linux查看二进制文件
在Linux中,查看二进制文件可以使用hexdump或xxd命令。 例如,要查看一个名为example.bin的二进制文件的内容,可以使用以下命令之一: 使用hexdump: bash hexdump -C example.bin使用xxd: bash xxd exam…...
营销翻车,杜国楹出面道歉,小罐茶的“大师作”故事仓皇结尾
“小罐茶,大师作”,这句slogan曾一度在央视平台长时间、高密度播放,成为家喻户晓的广告词,也打响了小罐茶品牌的名号。但同时,市场上关于“大师作”真实性的质疑也从未停息。 就在6月25日小罐茶十二周年发布会上&#…...
linux server下人脸检测与识别服务程序的系统架构设计
一、绪论 1.1 定义 1.2 研究背景及意义 1.3 相关技术综述 二、人脸检测与识别技术概述 2.1 人脸检测原理与算法 2.2 人脸识别技术及方法 2.3 人脸识别过程简介 三、人脸检测与识别服务程序的系统架构 3.1 系统架构设计 3.2 技术实现流程 四、后续设计及经验瞎谈 4.…...
安装CLion配置opencv和torch环境
配置操作如图,源码见底部附录部分 安装CLion 官网下载 创建项目 设置环境 调整类型为release 配置opencv和项目 编译环境 编译后 重启CLion 测试opencv环境 测试代码 运行main.cpp显示图片 测试torch环境 没标红表示配置成功 附件 CMakeList.txt cmake_mi…...
[leetcode]number-of-longest-increasing-subsequence
. - 力扣(LeetCode) class Solution { public:int findNumberOfLIS(vector<int> &nums) {int n nums.size(), maxLen 0, ans 0;vector<int> dp(n), cnt(n);for (int i 0; i < n; i) {dp[i] 1;cnt[i] 1;for (int j 0; j < i…...
[MYSQL] MYSQL库的操作
前言 本文主要介绍MYSQL里 库 的操作 请注意 : 在MYSQL中,命令行是不区分大小写的 1.创建库 create database [if not exists] database_name [charsetutf8 collateutf8_general_ci] ...] create database 是命名语法,不可省略[if not exists] 如果不存在创建,如果存在跳过…...
数字黄金 vs 全球计算机:比特币与以太坊现货 ETF 对比
撰文:Andrew Kang 编译:J1N,Techub News 本文来源香港Web3媒体:Techub News 比特币现货 ETF 的通过为许多新买家打开了进入加密货币市场的大门,让他们可以在投资组合中配置比特币。但以太坊现货 ETF 的通过…...
互联网直播/点播技术与平台创新应用:视频推拉流EasyDSS案例分析
随着互联网技术的快速发展,直播/点播平台已成为信息传播和娱乐的重要载体。特别是在电视购物领域,互联网直播/点播平台与技术的应用,不仅为用户带来了全新的购物体验,也为商家提供了更广阔的营销渠道。传统媒体再一次切实感受到了…...
怎么在线电脑上做图片二维码?在线3步图片转活码的制作方法
图片怎么才能做成二维码展示呢?图片生成二维码的方式能够在手机上查看图片,有利于图片的快速分享,通过这种方法能够减少对内存的占用,也提高了用户获取图片的便利性。通过生成图片活码能够不断提供最新的图片给用户展示࿰…...
lighttpd安装和配置https
apt install lighttpd apt-get install php-cgi lighttpd-enable-mod fastcgi fastcgi-php service lighttpd force-reload lighttpd配置https sudo nano /etc/lighttpd/lighttpd.conf加入: server.modules ("mod_openssl") $SERVER["socket&quo…...
淘客返利平台的API设计与安全
淘客返利平台的API设计与安全 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿! 在构建淘客返利平台时,API设计和安全是两个至关重要的方面。API设计…...
SQL面试真题解答 SQL求连续五天上升 (SQL窗口函数使用)
SQL面试真题解答 SQL求连续五天上升 (SQL窗口函数使用) sql进阶:求某个日期的连续上涨天数 求解连续区间是数据分析、数据仓库笔试面试中常考的SQL题目,今天分享笔试面试题,期待各位拿到心仪的offer或有所收获! 一…...
39 - 安全技术与防火墙
39、安全技术和防火墙 一、安全技术 入侵检测系统:特点是不阻断网络访问,主要是提供报警和事后监督。不主动介入,默默看着你(监控)。 入侵防御系统:透明模式工作,数据包,网络监控…...
Python学习笔记26:进阶篇(十五)常见标准库使用之性能测试cProfile模块学习使用
前言 本文是根据python官方教程中标准库模块的介绍,自己查询资料并整理,编写代码示例做出的学习笔记。 根据模块知识,一次讲解单个或者多个模块的内容。 教程链接:https://docs.python.org/zh-cn/3/tutorial/index.html 本文主要…...
python中类的继承详解
面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展 (1)在类的继承中,存在父类跟子类,子类可以继…...
社交风潮塑造者:探索用户在Facebook的影响力
在当今数字化社会中,Facebook不仅是人们社交互动的主要平台,更是塑造社交风潮和文化趋势的重要力量。本文将从另一个角度深入探讨用户在Facebook上的影响力,探索其如何通过个人行为和互动,影响和改变社会的各个方面。 个人表达和内…...
Kotlin设计模式:代理模式详解
Kotlin设计模式:代理模式详解 在软件开发中,设计模式是解决常见问题的一种优雅方法。本文将介绍Kotlin中的代理模式(Proxy Pattern),其应用场景,以及如何通过实例代码实现这一模式。 代理模式的目的 代理…...
PostgreSQL逻辑备份-pg_dump
1.pg_dump备份恢复 pg_dump 是一个逻辑备份工具。使用 pg_dump 可以在数据库处于使用状态下进行一致 性的备份, 它不会阻塞其他用户对数据库的访问 。 一致性备份是 pg_dump 开始运行时,给数据库打了一个快照,且在 pg_dump 运行过程 中发生…...
UG_NX11.0之Windows11中安装出错及解决方法
UG_NX11.0之Windows11中安装出错及解决方法 文章目录 UG_NX11.0之Windows11中安装出错及解决方法1. 安装出错2. 解决方法1. 设置以兼容性模式运行2. 配置环境变量 3. 再次安装问题解决4. 安装后可删除配置的环境变量(可选) 1. 安装出错 以管理员身份运行Launch.exe,如下 点击D…...
android view 设置过 transalationY/X 后 marginTop/marginStart/Left 不变
在 Android 开发中,当你对一个视图(View)设置了 translationY 属性后,这个视图的 marginTop 属性实际上并不会改变。这是因为 translationY 只会影响视图的绘制位置,而不会改变视图的布局参数。换句话说,translationY 是一个运行时…...
解释在Android中如何实现本地存储,包括SQLite数据库和SharedPreferences。
在Android开发中,本地存储是不可或缺的一部分,它允许应用程序在用户的设备上保存和检索数据。两种常见的本地存储方式是SQLite数据库和SharedPreferences。下面我将从技术难点、面试官关注点、回答吸引力和代码举例四个方面来详细解释如何在Android中实现…...
鸿蒙开发 之 健康App案例
1.项目介绍 该项目是记录用户日常饮食情况,以及针对不同食物摄入营养不同会有对应的营养摄入情况和日常运动消耗情况,用户可以自己添加食品以及对应的热量。 1.1登陆页 1.2饮食统计页 1.3 食物列表页 2.登陆页 2.1自定义弹框 import preferences from oh…...
官方网站、门户网站是什么意思?/怎么寻找网站关键词并优化
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼我要做个rolldice的小游戏,然后这是我的完整的code,我想直接把bank method 里面的那几个variable用在下面的checkwin method里面,但是总是显示找不到variable,应该是超过scope了。我想…...
网站做广告投放 做销售线索预估/推广普通话的宣传语
相信很多app中都有通过拍照或者从相册中选择的方式设置并上传头像的功能。如下是我之前一个项目中通过相册或者拍照获取图片的一个功能(照片来源于网络)。现在把代码贴出来,大家使用时(点击imageView或者button时)&…...
加速wordpress 插件/网络推广引流是做什么工作
香蕉苹果是一种服用以后会令人造成愉快情绪的新鲜水果,它能够对脑神经传出激动的数据信号,进而使大家维持愉快,产生欢乐。那麼怀孕可以吃香蕉苹果吗?接下去一起来瞧瞧吧。怀孕可以吃香蕉苹果吗怀孕可以吃香蕉苹果,可是…...
网站备案步骤/2345网址大全下载到桌面
1、使用异步任务加载网络上的图片 我们可以打开这个网址:http://img1.3lian.com/img2011/07/20/05.jpg可以看到一副很好看的图片,我们就要把这个图片显示出来,首先,还是先要布局,我们要显示一幅图片,所以我…...
网站推广软件推广/做app软件大概多少钱
最近想在公司机器上使用耳机,接到前端插口上,无反应,无声音。接到后端,有反应,有声音。估计是机箱和主板的音频线没有接好。遂开机箱查看,得类似图如下:我的主板是8i945P-G,此图红圈…...
好看的网站首页/如何创建自己的卡网
虽然到现在为止,留言中还没有一个人看好 Dojo ,但是我还是准备继续写下去,不保证能写完,也许哪天不想写了,或者另有所爱了,可能就结束了,呵呵。 另外,相对于效率,我还是更…...