QT實(shí)現(xiàn)貪吃蛇游戲
為了熟悉QT的相關(guān)知識,我用了大約8個(gè)小時(shí)的時(shí)間用QT再次寫了一遍貪吃蛇。
因?yàn)镼T的機(jī)制和平時(shí)寫的程序流程不同,所以程序中可能沒有遵守代碼規(guī)范。
運(yùn)行效果:
程序內(nèi)除了實(shí)現(xiàn)貪吃蛇的基本功能外,還添加了記錄得分、調(diào)節(jié)游戲速度、重新開始游戲等功能。
游戲內(nèi)容使用QPainter類進(jìn)行繪制。
編譯環(huán)境:
Windows Qt 5.9.0 Qt Creator 4.3.0
思路:
數(shù)組存儲蛇節(jié)點(diǎn)坐標(biāo)的貪吃蛇游戲思路。
因?yàn)榫帉戇^程中使用了分文件編寫,且QT框架的其他部分較多,這里僅展示程序?qū)崿F(xiàn)主要代碼。
代碼:
MainWindow.h 主窗口類頭文件
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QPainter> //畫家類 #include "snake.h" //蛇類 #include <QKeyEvent> //鍵盤事件 #include "food.h" //食物類 #include <QTimer> //定時(shí)器類 namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); //繪圖事件 void paintEvent(QPaintEvent *); //游戲結(jié)束的情況 void GameOver(); private: Ui::Widget *ui; Snake snake; //蛇對象 char key = 'd'; //接收鍵值,初始向右 Food food; //食物對象 //創(chuàng)建定時(shí)器 QTimer *timer = new QTimer(this); bool gameflag = false;//游戲結(jié)束標(biāo)記 int score = 0; //記錄得分 int timerspeed = 200; //定時(shí)器速度 bool bugflag = false; //用于解決操控過快導(dǎo)致撞死自己的bug的標(biāo)志 //鍵盤事件,改變鍵值 void keyPressEvent(QKeyEvent *ev); }; #endif // WIDGET_H
MainWindow.cpp函數(shù)實(shí)現(xiàn)
#include "MainWindow.h" #include "ui_widget.h" #include <QLabel> #include <QPushButton> //主窗口構(gòu)造函數(shù) Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); //初始化出.ui界面 //一個(gè)格子寬高25像素,地圖寬高600像素,每行有24個(gè)格子 //設(shè)置固定窗口大小 setFixedSize(1000,600); //設(shè)置得分標(biāo)簽控件的屬性 ui->label->setFont(QFont("黑體", 20, QFont::Bold, false)); //設(shè)置游戲速度標(biāo)簽內(nèi)容 ui->label_2->setFont(QFont("楷體", 16, QFont::Bold, false)); ui->label_2->setText("游戲速度:"); //滑動(dòng)條控件,這里將數(shù)值按一定比例放大縮小 ui->horizontalSlider->setValue(200 >> 2); //監(jiān)聽滑動(dòng)條控件滑動(dòng)時(shí),改變定時(shí)器速度為滑動(dòng)條的值 connect(ui->horizontalSlider,QSlider::valueChanged,[=]() { timerspeed = ui->horizontalSlider->value() << 2; }); //設(shè)置重新開始按鈕屬性和內(nèi)容 ui->pushButton_3->setFont(QFont("黑體",12)); ui->pushButton_3->setText("重新開始"); //監(jiān)聽重新開始按鈕 connect(ui->pushButton_3,QPushButton::clicked,[=]() { snake.Reset(); //重置蛇 score = 0; //得分清0 key = 'd'; //key值向右 timerspeed = 200 << 2;//重置游戲速度 timer->start(timerspeed);//重置定時(shí)器 ui->horizontalSlider->setValue(200 >> 2);//重置滑動(dòng)條 gameflag = false; //重置游戲結(jié)束標(biāo)志 }); //開啟定時(shí)器 timer->start(timerspeed); //監(jiān)聽定時(shí)器的信號,執(zhí)行表達(dá)式內(nèi)容 connect(timer,&QTimer::timeout,[=]() { timer->start(timerspeed); //調(diào)整定時(shí)器的速度 snake.Move(key); //蛇移動(dòng)函數(shù) //吃到食物的情況 (food.getfoodX() == snake.snakevec.at(0).x && food.getfoodY() == snake.snakevec.at(0).y) ? score++, food.randfood(): //得分+1,隨機(jī)產(chǎn)生一個(gè)食物坐標(biāo) snake.snakevec.pop_back(); //刪除蛇尾 GameOver(); //游戲失敗的情況 update(); //調(diào)用繪圖函數(shù) //更新標(biāo)簽控件的文本內(nèi)容 ui->label->setText(QString("得分:%1").arg(score)); }); } //游戲失敗情況 void Widget::GameOver() { //撞墻失敗 if(snake.snakevec.at(0).x >= 24 * 25 || snake.snakevec.at(0).x < 0 || snake.snakevec.at(0).y < 0 || snake.snakevec.at(0).y >= 24 * 25) { gameflag = true; timer->stop(); //暫停定時(shí)器 return; } //撞自己失敗 for(int i = 1; i < snake.snakevec.size(); i++) { if(snake.snakevec.at(0).x == snake.snakevec.at(i).x && snake.snakevec.at(0).y == snake.snakevec.at(i).y) gameflag = true, timer->stop(); } } //繪圖事件 void Widget::paintEvent(QPaintEvent *) { //創(chuàng)建畫家對象,指定繪圖設(shè)備為this主窗口 QPainter painter(this); //設(shè)置畫刷為紅色 QBrush brush1(Qt::red); //讓畫家使用畫刷 painter.setBrush(brush1); //畫食物 painter.drawRect(QRect(food.getfoodX(),food.getfoodY(),25,25)); //設(shè)置畫刷為黑色 QBrush brush2(Qt::blue); painter.setBrush(brush2); //遍歷蛇坐標(biāo)容器,畫出代表蛇身的矩形 for(auto snakenodei : snake.snakevec) //蛇頭畫圓形 (snakenodei.x == snake.snakevec.at(0).x && snakenodei.y == snake.snakevec.at(0).y) ? //蛇頭畫圓形 painter.setRenderHint(QPainter::Antialiasing), //用抗鋸齒畫圓 painter.drawEllipse(QPoint(snakenodei.x + 12,snakenodei.y + 12),12,12): //蛇身畫矩形 painter.drawRect(QRect(snakenodei.x,snakenodei.y,25,25)); bugflag = false; //在畫出蛇之后將標(biāo)志設(shè)為假 //設(shè)置畫刷為黑色 QBrush brush3(QColor(128, 64, 0)); painter.setBrush(brush3); //畫出墻壁 for(int i = 0; i < 24; i++) painter.drawRect(QRect(25 * 25, i * 25, 25, 25)); //游戲結(jié)束時(shí)的繪圖 if(gameflag) { //設(shè)置文字屬性 QFont font("楷體", 80, QFont::Bold, false); painter.setFont(font); //使用字體 painter.drawText(QRect(240, 200, 1000, 500), "游戲結(jié)束"); //畫出游戲結(jié)束文字 } } //鍵盤事件,改變貪吃蛇移動(dòng)方向 void Widget::keyPressEvent(QKeyEvent *ev) { if(bugflag) //bug標(biāo)志為真直接返回 return; switch (ev->key()) { case Qt::Key_W: if(key == 's') break; //按下與當(dāng)前方向相反按鍵時(shí)break key = 'w'; bugflag = true; break; //按鍵之后將標(biāo)志設(shè)為真 case Qt::Key_S: if(key == 'w') break; key = 's'; bugflag = true; break; case Qt::Key_A: if(key == 'd') break; key = 'a'; bugflag = true; break; case Qt::Key_D: if(key == 'a') break; key = 'd'; bugflag = true; break; case Qt::Key_Space: //空格鍵暫停,這里有點(diǎn)問題 timer->stop(); break; default: //其他鍵重啟定時(shí)器 timer->start(timerspeed); } } //析構(gòu) Widget::~Widget() { delete ui; }
snake.h 蛇類頭文件
#ifndef SNAKE_H #define SNAKE_H #include <QWidget> #include <QVector> //Qt動(dòng)態(tài)數(shù)組類 class Snake : public QWidget { Q_OBJECT private: //蛇坐標(biāo)結(jié)構(gòu) struct Snakecoor { int x; int y; }; public: explicit Snake(QWidget *parent = nullptr); //蛇坐標(biāo)容器 QVector<Snakecoor> snakevec; //蛇移動(dòng)主要函數(shù) void Move(char key); //根據(jù)key值確定蛇的移動(dòng)方向 void DeteDirMove(char key, Snakecoor &nexthead); //重置蛇 void Reset(); signals: public slots: }; #endif // SNAKE_H
snake.cpp 蛇類函數(shù)實(shí)現(xiàn)
#include "snake.h" //構(gòu)造函數(shù)初始化一條蛇 Snake::Snake(QWidget *parent) : QWidget(parent) { Snakecoor snakenode; //臨時(shí)結(jié)構(gòu)變量用于創(chuàng)建蛇 for (int i = 5; i >= 0; i--) //從右向左創(chuàng)建5節(jié)蛇身,容器的第一個(gè)元素為蛇頭 { snakenode.x = 25 * 8 + i * 25;//每個(gè)格子寬25像素 snakenode.y = 25 * 8; snakevec.push_back(snakenode);//將蛇節(jié)點(diǎn)插入到數(shù)組中 } } //確定蛇的移動(dòng)方向,確定新蛇頭的坐標(biāo)位置 inline void Snake::DeteDirMove(char key, Snakecoor &nexthead) { switch (key) { case 'w': //新蛇頭坐標(biāo)根據(jù)舊蛇頭坐標(biāo)改變 nexthead.x = snakevec.front().x; nexthead.y = snakevec.front().y - 25; break; case 's': nexthead.x = snakevec.front().x; nexthead.y = snakevec.front().y + 25; break; case 'a': nexthead.x = snakevec.front().x - 25; nexthead.y = snakevec.front().y; break; case 'd': nexthead.x = snakevec.front().x + 25; nexthead.y = snakevec.front().y; } } //蛇移動(dòng)主要函數(shù) void Snake::Move(char key) { Snakecoor nexthead; //創(chuàng)建一個(gè)新的蛇頭 DeteDirMove(key, nexthead); //確定新蛇頭的位置 snakevec.insert(snakevec.begin(), nexthead); //將新蛇頭插入到容器頭部 } //重置蛇函數(shù) void Snake::Reset() { snakevec.clear(); //清空容器 //初始化蛇 Snakecoor snakenode; for (int i = 5; i >= 0; i--) { snakenode.x = 25 * 8 + i * 25; snakenode.y = 25 * 8; snakevec.push_back(snakenode); } }
food.h 食物類頭文件
#ifndef FOOD_H #define FOOD_H #include <QWidget> class Food : public QWidget { Q_OBJECT public : int food_x = 0; //食物坐標(biāo) int food_y = 0; public: explicit Food(QWidget *parent = nullptr); void randfood(); //隨機(jī)產(chǎn)生食物坐標(biāo) int getfoodX(); //返回食物坐標(biāo) int getfoodY(); signals: public slots: }; #endif // FOOD_H
food.cpp 食物類函數(shù)實(shí)現(xiàn)
#include "food.h" #include <ctime> Food::Food(QWidget *parent) : QWidget(parent) { randfood(); //創(chuàng)建對象時(shí)產(chǎn)生就一個(gè)隨機(jī)坐標(biāo) } //隨機(jī)產(chǎn)生食物坐標(biāo) void Food::randfood() { srand((unsigned)time(NULL)); food_x = (rand() % 24) * 25; food_y = (rand() % 24 )* 25; } //獲取食物的坐標(biāo) int Food::getfoodX() { return food_x; } int Food::getfoodY() { return food_y; }
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- C++實(shí)現(xiàn)貪吃蛇游戲
- C++代碼實(shí)現(xiàn)貪吃蛇小游戲
- 基于easyx的C++實(shí)現(xiàn)貪吃蛇
- C++控制臺循環(huán)鏈表實(shí)現(xiàn)貪吃蛇
- C++控制臺實(shí)現(xiàn)貪吃蛇游戲
- C++通過類實(shí)現(xiàn)控制臺貪吃蛇
- C++結(jié)構(gòu)體數(shù)組實(shí)現(xiàn)貪吃蛇
- C++ vector容器實(shí)現(xiàn)貪吃蛇小游戲
- C++實(shí)現(xiàn)簡單貪吃蛇游戲
- 利用C/C++實(shí)現(xiàn)較完整貪吃蛇游戲
- C/C++實(shí)現(xiàn)貪吃蛇逐步運(yùn)動(dòng)效果
- C++基于控制臺實(shí)現(xiàn)的貪吃蛇小游戲
- 貪吃蛇游戲C++命令行版實(shí)例代碼
相關(guān)文章
Qt實(shí)現(xiàn)定時(shí)器的兩種方法分享
這篇文章主要為大家詳細(xì)介紹了Qt中實(shí)現(xiàn)定時(shí)器的兩種不同方法,文中的示例代碼講解詳細(xì),對我們了解Qt有一定的幫助,感興趣的可以跟隨小編一起學(xué)習(xí)一下2022-11-11C++中聲明類的class與聲明結(jié)構(gòu)體的struct關(guān)鍵字詳解
這篇文章主要介紹了C++中聲明類的class與聲明結(jié)構(gòu)體的struct關(guān)鍵字,默認(rèn)情況下結(jié)構(gòu)的所有成員均是公有的,而類的所有成員是私有的,需要的朋友可以參考下2016-01-01c++11中關(guān)于std::thread的join的詳解
這篇文章主要介紹了c++11中關(guān)于std::thread的join詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03C++?超詳細(xì)分析多態(tài)的原理與實(shí)現(xiàn)
這篇文章主要介紹了C++多態(tài)的原理與實(shí)現(xiàn),多態(tài)是一種面向?qū)ο蟮脑O(shè)計(jì)思路,本身和C++不是強(qiáng)綁定的,其他語言當(dāng)中一樣有多態(tài),只不過實(shí)現(xiàn)的方式可能有所不同。下面來一起了解更多詳細(xì)內(nèi)容吧2022-03-03C語言數(shù)據(jù)結(jié)構(gòu) 棧的基礎(chǔ)操作
這篇文章主要介紹了C語言數(shù)據(jù)結(jié)構(gòu) 棧的基礎(chǔ)操作的相關(guān)資料,需要的朋友可以參考下2017-05-05win10環(huán)境下C++ vs2015編譯opencv249的教程
這篇文章主要介紹了win10環(huán)境下C++ vs2015編譯opencv249的教程,本文分步驟給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03