贪吃蛇游戏是⼀款休闲益智类游戏。它通过控制蛇头方向吃食物,从而使得蛇变得越来越长。在本游戏中设置了上下左右四个⽅向键来控制蛇的移动方向。⻝物的产⽣是随机⽣成的,当蛇每吃⼀次⻝物就会增加⼀节身体,同时游戏积分也会相应的加⼀。在本游戏的设计中,蛇的⾝体会越吃越长,身体越长对应的难度就越⼤,因为⼀旦蛇头和⾝体相交游戏就会结束。

当用户点击 “开始游戏” 按钮之后,就会进⼊到关卡选择界面。

在关卡选择界面上设置了三个游戏模式按钮,分别是:简单模式、正常模式、困难模式;⼀个 “历史战绩” 按钮;⼀个返回游戏大厅界⾯的按钮。

在游戏界⾯,如果想要开始游戏,⾸先点击 “开始” 按钮,此时蛇就会移动并且还有背景⾳效。如果想要暂停游戏,那么点击 “暂停” 按钮即可。当我们在游戏时,可以通过右边控制区域的上下左右⽅向键来控制蛇的移动。当蛇每吃⼀次⻝物时,伴随有吃⻝物的⾳效,蛇⾝会增加⼀节⻓度,并且分数
积分也会相应的加⼀。最后在控制区域的右下⻆布局了⼀个 “退出” 按钮,当点击 “退出” 按钮时,就会有⼀个弹窗提⽰,如下
如果我们点击 “Ok” ,则会退出到游戏关卡选择界⾯,此时我们可以重新选择游戏模式。如果点击“Cancel” ,则不会退出游戏,我们还是处在当前游戏房间界⾯。
游戏大厅界面比较简单, 只有⼀个背景图和⼀个按钮
void GameHall::paintEvent(QPaintEvent *event) { //实例化画家对象 QPainter painter(this); //实例化绘图设备 QPixmap pix(":res/game_hall.png"); //绘画 painter.drawPixmap(0,0,this->width(),this->height(),pix); } GameHall::GameHall(QWidget *parent) : QWidget(parent) , ui(new Ui::GameHall) { ui->setupUi(this); this->setFixedSize(1500,1000);//设置窗口大小 this->setWindowTitle(QString("贪吃蛇游戏")); this->setWindowIcon(QIcon(":res/ico.png"));//设置窗口图标 // QFont font("华文行楷",20); QPushButton * strbutton = new QPushButton(this); strbutton->setText("开始游戏"); strbutton->setFont(font); strbutton->move(650,700); strbutton->setShortcut(QKeySequence(Qt::Key_Space)); strbutton->setStyleSheet("QPushButton{border:0px}");//给按钮设置样式 去除边框 GameSelect * gameSelect = new GameSelect; connect(strbutton,&QPushButton::clicked,[=](){ this->close();//当前窗口关闭 gameSelect->setGeometry(this->geometry());//设置第二个窗口于当前窗口一致 gameSelect->show();//新的窗口打开 QSound::play(":res/clicked.wav"); }); }
- 这里的Qfound类,使用需要在
.pro的文件中加上QT += core gui multimedia- 这里使用
strbutton->setShortcut(QKeySequence(Qt::Key_Space));给按钮添加了快捷键- 使用
strbutton->setStyleSheet("QPushButton{border:0px}");去除按钮边框样式- 通过槽函数跳转到新的窗口 ,在槽函数中使用了
Lambda表达式
通过QSound创建音频对象,使点击按钮有声音

关卡选择界⾯包含⼀个背景图和五个按钮,背景图的绘制和游戏⼤厅背景图绘制⼀样,同样使用的是Qt中的绘图事件,下面依次介绍。
void GameHall::paintEvent(QPaintEvent *event) { //实例化画家对象 QPainter painter(this); //实例化绘图设备 QPixmap pix(":res/game_hall.png"); //绘画 painter.drawPixmap(0,0,this->width(),this->height(),pix); } #include "gameselect.h" #include"gameroom.h" #include #include #include"gamehall.h" #include #include GameSelect::GameSelect(QWidget *parent) : QWidget(parent) { this->setFixedSize(1500,1000);//设置窗口大小 this->setWindowIcon(QIcon(":res/ico.png")); this->setWindowTitle("游戏关卡选择"); QPushButton* backBtn = new QPushButton(this);//返回按钮 backBtn->move(1400,900); backBtn->setIcon(QIcon(":res/back.png")); backBtn->setShortcut(QKeySequence(Qt::Key_Escape)); connect(backBtn,&QPushButton::clicked,[=](){ this->close(); GameHall * gameHall = new GameHall; gameHall->show(); QSound::play(":res/clicked.wav"); }); QFont font("华文行楷",20); gameroom*gameRoom = new gameroom; QPushButton* simpleBtn = new QPushButton(this); simpleBtn->move(650,300); simpleBtn->setFont(font); simpleBtn->setText("简单模式"); connect(simpleBtn,&QPushButton::clicked,[=](){ this->close(); gameRoom->setGeometry(this->geometry()); gameRoom->show(); }); QPushButton*normalBtn = new QPushButton(this); normalBtn->move(650,400); normalBtn->setFont(font); normalBtn->setText("正常模式"); connect(normalBtn,&QPushButton::clicked,[=](){ this->close(); gameRoom->setGeometry(this->geometry()); gameRoom->show(); }); QPushButton*hardBtn = new QPushButton(this); hardBtn->move(650,500); hardBtn->setFont(font); hardBtn->setText("困难模式"); connect(hardBtn,&QPushButton::clicked,[=]{ this->close(); gameRoom->setGeometry(this->geometry()); gameRoom->show(); }); QPushButton*hisBtn = new QPushButton(this); hisBtn->move(650,600); hisBtn->setFont(font); hisBtn->setText("历史战绩"); } void GameSelect::paintEvent(QPaintEvent *event) { QPainter painter(this);//实例化画家对象 QPixmap pix(":res/game_select.png"); painter.drawPixmap(0,0,this->width(),this->height(),pix); }
connect(hardBtn,&QPushButton::clicked,[=]{ this->close(); gameRoom->setGeometry(this->geometry()); gameRoom->show(); });
通过关联信号槽,使得可以选择游戏模式,首先把当前窗口关闭,然后显示新的窗口,在设置与当前窗口的大小一样
游戏房间界面包含下面几个部分:
怎么让蛇动起来?
- 我们可以⽤⼀个链表表示贪吃蛇,⼀个小方块表示蛇的⼀个节点, 我们设置蛇的默认⻓度为3;
- 向上移动的逻辑就是在蛇的上方加⼊⼀个小方块, 然后把最后⼀个小⽅块删除即可
- 需要用到定时器Qtimer 每100 - 200ms 重新渲染
怎么判断蛇有没有吃到食物?
- 判断蛇头和食物的坐标是否相交,
怎么控制蛇的移动?
- 借助QT的实践机制实现, 重写keyPressEvent即可, 在函数中监控想要的键盘事件即可
- 通过绘制四个按钮,使⽤信号和槽的机制控制蛇的上、下、左、右移动方向
#ifndef GAMEROOM_H #define GAMEROOM_H #include #include enum class SnakeDirect { UP=0, DOWN, LEFT, RIGHT }; class gameroom : public QWidget { Q_OBJECT public: explicit gameroom(QWidget *parent = nullptr); //重写绘图事件 void paintEvent(QPaintEvent *event); void moveUp(); void moveDown(); void moveLeft(); void moveRight(); bool checkFail(); void createNewFood(); void setTimeout(int timeout){moveTime=timeout;} private: const int KSnakeNodeWidth = 20; const int KSnakeNodeHeight = 20; const int KDefaultTimeout = 200;//移动速度 QList snakeList;//表示链表 QRectF foodRect;//食物 SnakeDirect moveDirect = SnakeDirect::UP;//默认移动方向 QTimer *timer;//定时器 bool isGameStart = false;//游戏的开始 QSound *sound; int moveTime = KDefaultTimeout; }; #endif // GAMEROOM_H 设置窗口大小、标题、图标等
gameroom::gameroom(QWidget *parent) : QWidget(parent) { this->setFixedSize(1500,1000); this->setWindowIcon(QIcon(":res/ico.png")); this->setWindowTitle("游戏房间"); } 蛇的移动方向为:上、下、左、右。通过在游戏房间中布局四个按钮来控制蛇的移动方向。
· 注意: 这里贪吃蛇不允许直接掉头, 比如当前是向上的, 不能直接修改为向下。
QPushButton*up= new QPushButton(this); QPushButton*down= new QPushButton(this); QPushButton*left= new QPushButton(this); QPushButton*right= new QPushButton(this); up->move(1320,750); down->move(1320,900); left->move(1220,825); right->move(1420,825); up->setText("↑"); // up->setShortcut(QKeySequence(Qt::Key_W)); down->setText("↓"); // down->setShortcut(QKeySequence(Qt::Key_S)); left->setText("←"); // left->setShortcut(QKeySequence(Qt::Key_A)); right->setText("→"); // left->setShortcut(QKeySequence(Qt::Key_D)); up->setStyleSheet("QPushButton{border:0px}"); down->setStyleSheet("QPushButton{border:0px}"); left->setStyleSheet("QPushButton{border:0px}"); right->setStyleSheet("QPushButton{border:0px}"); QFont ft("宋体",36); up->setFont(ft); down->setFont(ft); right->setFont(ft); left->setFont(ft); connect(up,&QPushButton::clicked,[=](){ if(moveDirect!= SnakeDirect::DOWN) { moveDirect = SnakeDirect::UP; } }); connect(down,&QPushButton::clicked,[=](){ if(moveDirect!= SnakeDirect::UP) { moveDirect = SnakeDirect::DOWN; } }); connect(left,&QPushButton::clicked,[=](){ if(moveDirect!= SnakeDirect::LEFT) { moveDirect = SnakeDirect::RIGHT; } }); connect(right,&QPushButton::clicked,[=](){ if(moveDirect!= SnakeDirect::RIGHT) { moveDirect = SnakeDirect::LEFT; } }); GameRoom::GameRoom(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { snakeList.push_back(QRectF(this->width()*0.5,this->height()*0.5,KSnakeNodeWidth,KSnakeNodeHeight)); moveUp(); moveUp(); moveUp(); //创建食物 createNewFood(); } moveUp() 的功能是将蛇向上移动⼀次, 即在上⽅新增⼀个节点, 但不删除尾部节点。
createNewFood() ⽅法的功能是随机创建⼀个⻝物节点:
void gameroom::createNewFood() { foodRect = QRectF(qrand()%(1500/KSnakeNodeWidth)*KSnakeNodeWidth, qrand()%(this->height()/KSnakeNodeHeight)*KSnakeNodeHeight, KSnakeNodeWidth,KSnakeNodeHeight); } 定时器的是为了实现每隔⼀段时间能处理移动的逻辑并且更新绘图事件。
timer = new QTimer(this); connect(timer,&QTimer::timeout,[=]{ int cnt =1 ; if(snakeList.front().intersects(foodRect)) { //intersects判断会不会相交 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; } } snakeList.pop_back();//删除最后一个节点 update(); }); 各个方向的移动主要在于更新矩形节点的坐标, 要注意的是⼀定要处理边界的情况, 当边界不够存储⼀个新的节点, 我们需要处理穿墙逻辑。
void gameroom::moveUp() { QPointF leftTop;//左上角坐标 QPointF rightBottom;//右下角坐标 auto snakeNode = snakeList.front();//头 int headx = snakeNode.x(); int heady = snakeNode.y(); if(heady < 0) { //穿墙了 leftTop = QPointF(headx,this->height()-KSnakeNodeHeight); } else { leftTop = QPointF(headx,heady- KSnakeNodeHeight); } rightBottom = leftTop + QPointF(KSnakeNodeWidth,KSnakeNodeHeight); snakeList.push_front(QRectF(leftTop,rightBottom));//更新到链表中 } void gameroom::moveDown() { QPointF leftTop;//左上角坐标 QPointF rightBottom;//右下角坐标 auto snakeNode = snakeList.front(); int headx = snakeNode.x(); int heady = snakeNode.y(); if(heady > this->height()) { leftTop = QPointF(headx,0); } else { leftTop =snakeNode.bottomLeft();//获取左下角做标 } rightBottom = leftTop + QPointF(KSnakeNodeWidth,KSnakeNodeHeight); snakeList.push_front(QRectF(leftTop,rightBottom)); } void gameroom::moveLeft() { QPointF leftTop;//左上角坐标 QPointF rightBottom;//右下角坐标 auto snakeNode = snakeList.front(); int headx = snakeNode.x(); int heady = snakeNode.y(); if(headx < 0) { leftTop = QPointF(1500 - KSnakeNodeWidth,heady); } else { leftTop = QPointF(headx - KSnakeNodeWidth,heady); } rightBottom = leftTop + QPointF(KSnakeNodeWidth,KSnakeNodeHeight); snakeList.push_front(QRectF(leftTop,rightBottom)); } void gameroom::moveRight() { QPointF leftTop;//左上角坐标 QPointF rightBottom;//右下角坐标 auto snakeNode = snakeList.front(); int headx = snakeNode.x(); int heady = snakeNode.y(); if(heady + KSnakeNodeWidth> 1200) { leftTop = QPointF(0,heady); } else { leftTop = snakeNode.bottomRight(); } rightBottom = leftTop + QPointF(KSnakeNodeWidth,KSnakeNodeHeight); snakeList.push_front(QRectF(leftTop,rightBottom)); } 重写基类的 paintEvent() 方法进行渲染:
void gameroom::paintEvent(QPaintEvent *event) { QPainter painter(this);//实例画家对象 QPixmap pix; pix.load(":res/game_room.png"); painter.drawPixmap(0,0,1200,1400,pix); pix.load(":res/bg1.png"); painter.drawPixmap(1200,0,300,1100,pix); //绘制蛇 //头 if(moveDirect == SnakeDirect::UP) { pix.load(":res/up.png"); } else if (moveDirect == SnakeDirect::DOWN) { pix.load(":res/down.png"); } else if (moveDirect == SnakeDirect::LEFT) { pix.load(":res/left.png"); } else if(moveDirect == SnakeDirect::RIGHT){ pix.load(":res/right.png"); } auto snakHead = snakeList.front(); painter.drawPixmap(snakHead.x(),snakHead.y(),snakHead.width(),snakHead.height(),pix); //身体 pix.load(":res/Bd.png"); for (int i= 1;i < snakeList.size()-1;i++) { auto node = snakeList.at(i); //at 获取每一个节点 painter.drawPixmap(node.x(),node.y(),node.width(),node.height(),pix); } //尾巴 auto snakeTail = snakeList.back(); painter.drawPixmap(snakeTail.x(),snakeTail.y(),snakeTail.width(),snakeTail.height(),pix); //食物 pix.load(":res/food.png"); painter.drawPixmap(foodRect.x(),foodRect.y(),foodRect.width(),foodRect.height(),pix); //分数 pix.load(":res/sorce_bg.png"); painter.drawPixmap(this->width()*0.85,this->height()*0.1,90,40,pix); QPen pen; pen.setColor(Qt::black); QFont font("方正舒体",22); painter.setFont(font); painter.setPen(pen); painter.drawText(this->width()*0.9,this->height()*0.06,QString("%1").arg(snakeList.size())); //往文件中写分数 int c = snakeList.size(); QFile file("C:/Users/zyy/Desktop/1.txt"); if(file.open(QIODevice::WriteOnly| QIODevice::Text)) { QTextStream out(&file); int num = c; out< pen.setColor(Qt::red); painter.setPen(pen); QFont font("方正舒体",22); painter.setFont(font); painter.drawText(this->width()*0.45,this->height()*0.5,QString("GAME OVER!")); timer->stop(); QSound::play(":res/gameover.wav"); sound->stop(); } } bool gameroom::checkFail() { for(int i = 0; i for(int j=i+1; j if(snakeList.at(i)==snakeList.at(j)) { return true; } } } return false; } QPushButton * strBtn = new QPushButton(this); QPushButton * stopBtn = new QPushButton(this); strBtn->move(1270,100); stopBtn->move(1270,170); strBtn->setText("开始"); strBtn->setShortcut(QKeySequence(Qt::Key_C+Qt::CTRL)); stopBtn->setText("暂停"); stopBtn->setShortcut(QKeySequence(Qt::Key_V+Qt::CTRL)); QFont font("楷体",20); strBtn->setFont(font); stopBtn->setFont(font); connect(strBtn,&QPushButton::clicked,[=]{ sound = new QSound(":res/Trepak.wav"); sound->play(); sound->setLoops(-1);//一直循环播放 isGameStart = true; timer->start(moveTime); }); connect(stopBtn,&QPushButton::clicked,[=]{ isGameStart = false; timer->stop(); sound->stop(); }); 当我们点击退出游戏按钮时,当前游戏房间窗⼝不会⽴即退出,而是会弹窗提示,提示我们是否要退出游戏,效果如下图示:
这个弹窗提示我们是通过 Qt 中的消息盒子来实现的,具体实现过程如下:
//退出游戏 QPushButton*ExitBtn = new QPushButton(this); ExitBtn->setText("退出游戏"); ExitBtn->move(1240,400); ExitBtn->setFont(font); QMessageBox *msg = new QMessageBox(this); QPushButton *ok = new QPushButton("ok"); QPushButton *canel = new QPushButton("canel"); msg->addButton(ok,QMessageBox::AcceptRole); msg->addButton(canel,QMessageBox::RejectRole); msg->setWindowTitle("退出游戏"); msg->setText("确认退出游戏吗"); connect(ExitBtn,&QPushButton::clicked,[=](){ msg->show(); msg->exec();//时间轮询 QSound::play("res/clicked.wav"); GameSelect *select = new GameSelect; if(msg->clickedButton()==ok) { this->close(); select->show(); } else { msg->close(); } }); } 对于历史战绩的获取我们是通过 Qt 中的读写文件操作来实现的。具体实现过程如下:
int c = snakeList.size(); QFile file("C:/Users/zyy/Desktop/1.txt"); if(file.open(QIODevice::WriteOnly| QIODevice::Text)) { QTextStream out(&file); int num = c; out< int c = snakeList.size(); QFile file("C:/Users/zyy/Desktop/1.txt"); if(file.open(QIODevice::WriteOnly| QIODevice::Text)) { QTextStream out(&file); int num = c; out< 
#ifndef GAMEHALL_H #define GAMEHALL_H #include QT_BEGIN_NAMESPACE namespace Ui { class GameHall; } QT_END_NAMESPACE class GameHall : public QWidget { Q_OBJECT public: GameHall(QWidget *parent = nullptr); ~GameHall(); //从写绘图事件 void paintEvent(QPaintEvent *event); private: Ui::GameHall *ui; }; #endif // GAMEHALL_H #ifndef GAMEROOM_H #define GAMEROOM_H #include #include enum class SnakeDirect { UP=0, DOWN, LEFT, RIGHT }; class gameroom : public QWidget { Q_OBJECT public: explicit gameroom(QWidget *parent = nullptr); //重写绘图事件 void paintEvent(QPaintEvent *event); void moveUp(); void moveDown(); void moveLeft(); void moveRight(); bool checkFail(); void createNewFood(); void setTimeout(int timeout){moveTime=timeout;} private: const int KSnakeNodeWidth = 20; const int KSnakeNodeHeight = 20; const int KDefaultTimeout = 200;//移动速度 QList snakeList;//表示链表 QRectF foodRect;//食物 SnakeDirect moveDirect = SnakeDirect::UP;//默认移动方向 QTimer *timer;//定时器 bool isGameStart = false;//游戏的开始 QSound *sound; int moveTime = KDefaultTimeout; }; #endif // GAMEROOM_H #ifndef GAMESELECT_H #define GAMESELECT_H #include class GameSelect : public QWidget { Q_OBJECT public: explicit GameSelect(QWidget *parent = nullptr); //绘图事件 void paintEvent(QPaintEvent *event); signals: }; #endif // GAMESELECT_H #include "gamehall.h" #include "ui_gamehall.h" #include #include #include #include #include"gameselect.h" #include GameHall::GameHall(QWidget *parent) : QWidget(parent) , ui(new Ui::GameHall) { ui->setupUi(this); this->setFixedSize(1500,1000);//设置窗口大小 this->setWindowTitle(QString("贪吃蛇游戏")); this->setWindowIcon(QIcon(":res/ico.png"));//设置窗口图标 // QFont font("华文行楷",20); QPushButton * strbutton = new QPushButton(this); strbutton->setText("开始游戏"); strbutton->setFont(font); strbutton->move(650,700); strbutton->setShortcut(QKeySequence(Qt::Key_Space)); strbutton->setStyleSheet("QPushButton{border:0px}");//给按钮设置样式 去除边框 GameSelect * gameSelect = new GameSelect; connect(strbutton,&QPushButton::clicked,[=](){ this->close();//当前窗口关闭 gameSelect->setGeometry(this->geometry());//设置第二个窗口于当前窗口一致 gameSelect->show();//新的窗口打开 QSound::play(":res/clicked.wav"); }); } GameHall::~GameHall() { delete ui; } void GameHall::paintEvent(QPaintEvent *event) { //实例化画家对象 QPainter painter(this); //实例化绘图设备 QPixmap pix(":res/game_hall.png"); //绘画 painter.drawPixmap(0,0,this->width(),this->height(),pix); } #include "gameroom.h" #include #include #include #include #include #include #include #include #include"gameselect.h" gameroom::gameroom(QWidget *parent) : QWidget(parent) { this->setFixedSize(1500,1000); this->setWindowIcon(QIcon(":res/ico.png")); this->setWindowTitle("游戏房间"); //初始化贪吃蛇 snakeList.push_back(QRectF(this->width()*0.5,this->height()*0.5,KSnakeNodeWidth,KSnakeNodeHeight)); moveUp(); moveUp(); moveUp(); //创建食物 createNewFood(); timer = new QTimer(this); connect(timer,&QTimer::timeout,[=]{ int cnt =1 ; if(snakeList.front().intersects(foodRect)) { //intersects判断会不会相交 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; } } snakeList.pop_back();//删除最后一个节点 update(); }); //开始暂停 QPushButton * strBtn = new QPushButton(this); QPushButton * stopBtn = new QPushButton(this); strBtn->move(1270,100); stopBtn->move(1270,170); strBtn->setText("开始"); strBtn->setShortcut(QKeySequence(Qt::Key_C+Qt::CTRL)); stopBtn->setText("暂停"); stopBtn->setShortcut(QKeySequence(Qt::Key_V+Qt::CTRL)); QFont font("楷体",20); strBtn->setFont(font); stopBtn->setFont(font); connect(strBtn,&QPushButton::clicked,[=]{ sound = new QSound(":res/Trepak.wav"); sound->play(); sound->setLoops(-1);//一直循环播放 isGameStart = true; timer->start(moveTime); }); connect(stopBtn,&QPushButton::clicked,[=]{ isGameStart = false; timer->stop(); sound->stop(); }); //方向控制 QPushButton*up= new QPushButton(this); QPushButton*down= new QPushButton(this); QPushButton*left= new QPushButton(this); QPushButton*right= new QPushButton(this); up->move(1320,750); down->move(1320,900); left->move(1220,825); right->move(1420,825); up->setText("↑"); up->setShortcut(QKeySequence(Qt::Key_W)); down->setText("↓"); down->setShortcut(QKeySequence(Qt::Key_S)); left->setText("←"); left->setShortcut(QKeySequence(Qt::Key_A)); right->setText("→"); left->setShortcut(QKeySequence(Qt::Key_D)); up->setStyleSheet("QPushButton{border:0px}"); down->setStyleSheet("QPushButton{border:0px}"); left->setStyleSheet("QPushButton{border:0px}"); right->setStyleSheet("QPushButton{border:0px}"); QFont ft("宋体",36); up->setFont(ft); down->setFont(ft); right->setFont(ft); left->setFont(ft); connect(up,&QPushButton::clicked,[=](){ if(moveDirect!= SnakeDirect::DOWN) { moveDirect = SnakeDirect::UP; } }); connect(down,&QPushButton::clicked,[=](){ if(moveDirect!= SnakeDirect::UP) { moveDirect = SnakeDirect::DOWN; } }); connect(left,&QPushButton::clicked,[=](){ if(moveDirect!= SnakeDirect::RIGHT) { moveDirect = SnakeDirect::LEFT; } }); connect(right,&QPushButton::clicked,[=](){ if(moveDirect!= SnakeDirect::LEFT) { moveDirect = SnakeDirect::RIGHT; } }); //退出游戏 QPushButton*ExitBtn = new QPushButton(this); ExitBtn->setText("退出游戏"); ExitBtn->move(1240,400); ExitBtn->setFont(font); QMessageBox *msg = new QMessageBox(this); QPushButton *ok = new QPushButton("ok"); QPushButton *canel = new QPushButton("canel"); msg->addButton(ok,QMessageBox::AcceptRole); msg->addButton(canel,QMessageBox::RejectRole); msg->setWindowTitle("退出游戏"); msg->setText("确认退出游戏吗"); connect(ExitBtn,&QPushButton::clicked,[=](){ msg->show(); msg->exec();//时间轮询 QSound::play("res/clicked.wav"); GameSelect *select = new GameSelect; if(msg->clickedButton()==ok) { this->close(); select->show(); } else { msg->close(); } }); } void gameroom::paintEvent(QPaintEvent *event) { QPainter painter(this);//实例画家对象 QPixmap pix; pix.load(":res/game_room.png"); painter.drawPixmap(0,0,1200,1400,pix); pix.load(":res/bg1.png"); painter.drawPixmap(1200,0,300,1100,pix); //绘制蛇 //头 if(moveDirect == SnakeDirect::UP) { pix.load(":res/up.png"); } else if (moveDirect == SnakeDirect::DOWN) { pix.load(":res/down.png"); } else if (moveDirect == SnakeDirect::LEFT) { pix.load(":res/left.png"); } else if(moveDirect == SnakeDirect::RIGHT){ pix.load(":res/right.png"); } auto snakHead = snakeList.front(); painter.drawPixmap(snakHead.x(),snakHead.y(),snakHead.width(),snakHead.height(),pix); //身体 pix.load(":res/Bd.png"); for (int i= 1;i < snakeList.size()-1;i++) { auto node = snakeList.at(i); //at 获取每一个节点 painter.drawPixmap(node.x(),node.y(),node.width(),node.height(),pix); } //尾巴 auto snakeTail = snakeList.back(); painter.drawPixmap(snakeTail.x(),snakeTail.y(),snakeTail.width(),snakeTail.height(),pix); //食物 pix.load(":res/food.png"); painter.drawPixmap(foodRect.x(),foodRect.y(),foodRect.width(),foodRect.height(),pix); //分数 pix.load(":res/sorce_bg.png"); painter.drawPixmap(this->width()*0.85,this->height()*0.1,90,40,pix); QPen pen; pen.setColor(Qt::black); QFont font("方正舒体",22); painter.setFont(font); painter.setPen(pen); painter.drawText(this->width()*0.9,this->height()*0.06,QString("%1").arg(snakeList.size())); //往文件中写分数 int c = snakeList.size(); QFile file("C:/Users/zyy/Desktop/1.txt"); if(file.open(QIODevice::WriteOnly| QIODevice::Text)) { QTextStream out(&file); int num = c; out< pen.setColor(Qt::red); painter.setPen(pen); QFont font("方正舒体",22); painter.setFont(font); painter.drawText(this->width()*0.45,this->height()*0.5,QString("GAME OVER!")); timer->stop(); QSound::play(":res/gameover.wav"); sound->stop(); } } void gameroom::moveUp() { QPointF leftTop;//左上角坐标 QPointF rightBottom;//右下角坐标 auto snakeNode = snakeList.front();//头 int headx = snakeNode.x(); int heady = snakeNode.y(); if(heady < 0) { //穿墙了 leftTop = QPointF(headx,this->height()-KSnakeNodeHeight); } else { leftTop = QPointF(headx,heady- KSnakeNodeHeight); } rightBottom = leftTop + QPointF(KSnakeNodeWidth,KSnakeNodeHeight); snakeList.push_front(QRectF(leftTop,rightBottom));//更新到链表中 } void gameroom::moveDown() { QPointF leftTop;//左上角坐标 QPointF rightBottom;//右下角坐标 auto snakeNode = snakeList.front(); int headx = snakeNode.x(); int heady = snakeNode.y(); if(heady > this->height()) { leftTop = QPointF(headx,0); } else { leftTop =snakeNode.bottomLeft();//获取左下角做标 } rightBottom = leftTop + QPointF(KSnakeNodeWidth,KSnakeNodeHeight); snakeList.push_front(QRectF(leftTop,rightBottom)); } void gameroom::moveLeft() { QPointF leftTop;//左上角坐标 QPointF rightBottom;//右下角坐标 auto snakeNode = snakeList.front(); int headx = snakeNode.x(); int heady = snakeNode.y(); if(headx < 0) { leftTop = QPointF(1500 - KSnakeNodeWidth,heady); } else { leftTop = QPointF(headx - KSnakeNodeWidth,heady); } rightBottom = leftTop + QPointF(KSnakeNodeWidth,KSnakeNodeHeight); snakeList.push_front(QRectF(leftTop,rightBottom)); } void gameroom::moveRight() { QPointF leftTop;//左上角坐标 QPointF rightBottom;//右下角坐标 auto snakeNode = snakeList.front(); int headx = snakeNode.x(); int heady = snakeNode.y(); if(heady + KSnakeNodeWidth> 1200) { leftTop = QPointF(0,heady); } else { leftTop = snakeNode.bottomRight(); } rightBottom = leftTop + QPointF(KSnakeNodeWidth,KSnakeNodeHeight); snakeList.push_front(QRectF(leftTop,rightBottom)); } bool gameroom::checkFail() { for(int i = 0; i for(int j=i+1; j if(snakeList.at(i)==snakeList.at(j)) { return true; } } } return false; } void gameroom::createNewFood() { foodRect = QRectF(qrand()%(1500/KSnakeNodeWidth)*KSnakeNodeWidth, qrand()%(this->height()/KSnakeNodeHeight)*KSnakeNodeHeight, KSnakeNodeWidth,KSnakeNodeHeight); } #include "gameselect.h" #include"gameroom.h" #include #include #include"gamehall.h" #include #include #include #include #include GameSelect::GameSelect(QWidget *parent) : QWidget(parent) { this->setFixedSize(1500,1000);//设置窗口大小 this->setWindowIcon(QIcon(":res/ico.png")); this->setWindowTitle("游戏关卡选择"); QPushButton* backBtn = new QPushButton(this);//返回按钮 backBtn->move(1400,900); backBtn->setIcon(QIcon(":res/back.png")); backBtn->setShortcut(QKeySequence(Qt::Key_Escape)); connect(backBtn,&QPushButton::clicked,[=](){ this->close(); GameHall * gameHall = new GameHall; gameHall->show(); QSound::play(":res/clicked.wav"); }); QFont font("华文行楷",20); gameroom*gameRoom = new gameroom; QPushButton* simpleBtn = new QPushButton(this); simpleBtn->move(650,300); simpleBtn->setFont(font); simpleBtn->setText("简单模式"); connect(simpleBtn,&QPushButton::clicked,[=](){ this->close(); gameRoom->setGeometry(this->geometry()); gameRoom->show(); gameRoom->setTimeout(300); }); QPushButton*normalBtn = new QPushButton(this); normalBtn->move(650,400); normalBtn->setFont(font); normalBtn->setText("正常模式"); connect(normalBtn,&QPushButton::clicked,[=](){ this->close(); gameRoom->setGeometry(this->geometry()); gameRoom->show(); gameRoom->setTimeout(200); }); QPushButton*hardBtn = new QPushButton(this); hardBtn->move(650,500); hardBtn->setFont(font); hardBtn->setText("困难模式"); connect(hardBtn,&QPushButton::clicked,[=]{ this->close(); gameRoom->setGeometry(this->geometry()); gameRoom->show(); gameRoom->setTimeout(300); }); QPushButton*hisBtn = new QPushButton(this); hisBtn->move(650,600); hisBtn->setFont(font); hisBtn->setText("历史战绩"); connect(hisBtn,&QPushButton::clicked,[=](){ QWidget *widget = new QWidget; widget->setWindowTitle("历史战绩"); widget->setFixedSize(500,300); QTextEdit *edit = new QTextEdit(widget); edit->setFont(font); edit->setFixedSize(500,300); QFile file("C:/Users/zyy/Desktop/1.txt"); file.open(QIODevice::ReadOnly);//读取内容 QTextStream in(&file); int data = in.readLine().toInt();//读取一行的数据 edit->append("得分为:"); edit->append(QString::number(data));//写入文本中 widget->show(); }); } void GameSelect::paintEvent(QPaintEvent *event) { QPainter painter(this);//实例化画家对象 QPixmap pix(":res/game_select.png"); painter.drawPixmap(0,0,this->width(),this->height(),pix); }