QT實(shí)現(xiàn)貪吃蛇游戲代碼詳解
一、新建一個(gè)Qt項(xiàng)目
新建Qt Widgets Application,項(xiàng)目名稱為HappySnake,基類選擇QWidget,類名默認(rèn)
二、添加要用到的頭文件
#include <QKeyEvent> #include <QRectF> #include <QPainter> #include <QPen> #include <QBrush> #include <QDebug> #include <QTimer> #include <QTime>
三、寫類聲明信息
- 貪吃蛇的本體使用小方框來代替
- 使用QList類來保存貪吃蛇的本體
- 使用定時(shí)器來設(shè)定刷新的時(shí)間
- 使用隨機(jī)函數(shù)生成獎(jiǎng)勵(lì)的節(jié)點(diǎn)
- 使用paintEvent來進(jìn)行繪圖
- keyPressEvent來監(jiān)測按鍵的按下,控制貪吃蛇的移動(dòng)
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
protected:
void paintEvent(QPaintEvent *);
void keyPressEvent(QKeyEvent *);
private:
void addTopRectF();
void addDownRectF();
void addLeftRectF();
void addRightRectF();
void deleteLastRectF();
bool snakeStrike();
enum Move{Left,Right,Up,Down};
protected slots:
void timeOut();
void rewardTimeOut();
private:
Ui::Widget *ui;
QList<QRectF> snake;//貪吃蛇本體
int snakeNodeWidth = 10;
int snakeNodeHeight = 10;
QTimer *timer;
QTimer *rewardTimer;
int time = 100;
int moveFlage = Up;
bool gameOver = false;
bool gameStart = false;
QList<QRectF> rewardNode;//獎(jiǎng)勵(lì)節(jié)點(diǎn)
};
四、對(duì)類函數(shù)的實(shí)現(xiàn)
構(gòu)造函數(shù)
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
resize(480,500);
//設(shè)置窗體背景色為黑色
setStyleSheet("QWidget{background:black}");
setWindowOpacity(0.8);//設(shè)置窗口的透明度
snake.append(QRectF(200,500,snakeNodeWidth,snakeNodeHeight));
addTopRectF();
addTopRectF();
//首先生成一個(gè)獎(jiǎng)勵(lì)節(jié)點(diǎn)
rewardNode.append(QRectF(100,100,snakeNodeWidth,snakeNodeWidth));
timer = new QTimer;
connect(timer, SIGNAL(timeout()),this,SLOT(timeOut()));
//timer->start(time);
rewardTimer = new QTimer;
connect(rewardTimer,SIGNAL(timeout()),this,SLOT(rewardTimeOut()));
//rewardTimer->start(time*30);
}
Widget::~Widget()
{
delete ui;
}
界面刷新
void Widget::timeOut()
{
int flage = 1;
for(int i=0; i<rewardNode.length(); i++){
if(rewardNode.at(i).contains(snake.at(0).topLeft()+QPointF(snakeNodeWidth/2,snakeNodeHeight/2))){
//if(snake.at(0).contains(rewardNode.at(i).x()+rewardNode.at(i).width()/2,rewardNode.at(i).y()+rewardNode.at(i).height()/2)){
if(rewardNode.at(i).width()>snakeNodeWidth){//額外獎(jiǎng)勵(lì)
flage += 2;
}
flage++;//正常獎(jiǎng)勵(lì)
rewardNode.removeAt(i);
break;
}
}
while(flage--){
switch (moveFlage) {
case Up:
addTopRectF();
break;
case Down:
addDownRectF();
break;
case Right:
addRightRectF();
break;
case Left:
addLeftRectF();
break;
default:
break;
}
}
deleteLastRectF();
update();
}
隨機(jī)獎(jiǎng)勵(lì)的生成
//隨機(jī)獎(jiǎng)勵(lì)
void Widget::rewardTimeOut()
{
qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
if(rewardNode.length() > 5){
rewardNode.removeAt(qrand()%5);
}
rewardNode.append(QRectF(qrand()%(this->width()/20)*20,qrand()%(this->height()/20)*20,snakeNodeWidth,snakeNodeWidth));
if(qrand()%5 == 3){
rewardNode.append(QRectF(qrand()%(this->width()/20)*20-5,qrand()%(this->height()/20)*20-5,snakeNodeWidth*2,snakeNodeWidth*2));
}
}
移動(dòng)
//向上移動(dòng)
void Widget::addTopRectF()
{
if(snake.at(0).y()-snakeNodeHeight < 0){
snake.insert(0,QRectF(QPointF(snake.at(0).x(),this->height()-snakeNodeHeight),
QPointF(snake.at(0).x()+snakeNodeWidth,this->height())));
}else{
snake.insert(0,QRectF(snake.at(0).topLeft()+QPointF(0,-snakeNodeHeight),snake.at(0).topRight()));
}
}
//向下移動(dòng)
void Widget::addDownRectF()
{
if(snake.at(0).y()+snakeNodeHeight*2 > this->height()){
snake.insert(0,QRectF(QPointF(snake.at(0).x(),snakeNodeHeight),
QPointF(snake.at(0).x()+snakeNodeWidth,0)));
}else{
snake.insert(0,QRectF(snake.at(0).bottomLeft(),snake.at(0).bottomRight()+QPointF(0,snakeNodeHeight)));
}
}
//向左移動(dòng)
void Widget::addLeftRectF()
{
if(snake.at(0).x()-snakeNodeWidth < 0){
snake.insert(0,QRectF(QPointF(this->width()-snakeNodeWidth,snake.at(0).y()),
QPointF(this->width(),snake.at(0).y()+snakeNodeHeight)));
}else{
snake.insert(0,QRectF(snake.at(0).topLeft()+QPointF(-snakeNodeWidth,0),snake.at(0).bottomLeft()));
}
}
//向右移動(dòng)
void Widget::addRightRectF()
{
if(snake.at(0).x()+snakeNodeWidth*2 > this->width()){
snake.insert(0,QRectF(QPointF(0,snake.at(0).y()),
QPointF(snakeNodeWidth,snake.at(0).y()+snakeNodeHeight)));
}else{
snake.insert(0,QRectF(snake.at(0).topRight(),snake.at(0).bottomRight()+QPointF(snakeNodeWidth,0)));
}
}
//刪除結(jié)尾數(shù)據(jù)
void Widget::deleteLastRectF()
{
snake.removeLast();
}
繪圖
//繪圖
void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
QPen pen;
QBrush brush;
QFont font("方正舒體",12,QFont::ExtraLight,false);
//反鋸齒
painter.setRenderHint(QPainter::Antialiasing);
pen.setColor(Qt::black);
brush.setColor(Qt::green);
brush.setStyle(Qt::SolidPattern);
painter.setPen(pen);
painter.setBrush(brush);
for(int i=0; i<snake.length(); i++){
painter.drawRect(snake.at(i));
}
brush.setColor(Qt::red);
painter.setBrush(brush);
for(int i=0; i<rewardNode.length(); i++){
painter.drawEllipse(rewardNode.at(i));
}
pen.setColor(Qt::white);
painter.setPen(pen);
painter.setFont(font);
painter.drawText(20,20,QString("當(dāng)前得分:")+QString("%1").arg(snake.length()));
if(snakeStrike()){
QFont font("方正舒體",30,QFont::ExtraLight,false);
painter.setFont(font);
painter.drawText((this->width()-300)/2,(this->height()-30)/2,QString("GAME OVER!"));
timer->stop();
rewardTimer->stop();
gameOver = true;
}
QWidget::paintEvent(event);
}
按鍵事件
void Widget::keyPressEvent(QKeyEvent *event)
{
switch(event->key()){
case Qt::Key_Up:
if(moveFlage != Down){
moveFlage = Up;
}
break;
case Qt::Key_Down:
if(moveFlage != Up){
moveFlage = Down;
}
break;
case Qt::Key_Right:
if(moveFlage != Left){
moveFlage = Right;
}
break;
case Qt::Key_Left:
if(moveFlage != Right){
moveFlage = Left;
}
break;
case Qt::Key_Enter:
case Qt::Key_Return:
if(gameOver){
snake.clear();
rewardNode.clear();
moveFlage = Up;
snake.append(QRectF(200,500,snakeNodeWidth,snakeNodeHeight));
addTopRectF();
addTopRectF();
//首先生成一個(gè)獎(jiǎng)勵(lì)節(jié)點(diǎn)
rewardNode.append(QRectF(100,100,snakeNodeWidth,snakeNodeWidth));
timer->start(time);
rewardTimer->start(time*30);
gameOver = false;
}
break;
case Qt::Key_Space:
if(gameStart && !gameOver){
timer->start(time);
rewardTimer->start(time*30);
gameStart = false;
}else if(!gameStart && !gameOver){
timer->stop();
rewardTimer->stop();
gameStart = true;
}
break;
default:
break;
}
}
判斷蛇身是否相撞
//判斷蛇頭是否和蛇身相撞
bool Widget::snakeStrike()
{
for(int i=0; i<snake.length(); i++){
for(int j=i+1; j<snake.length(); j++){
if(snake.at(i) == snake.at(j)){
return true;
}
}
}
return false;
}
五、結(jié)束
實(shí)現(xiàn)的效果:


總結(jié):
只是簡單的使用了paintevent進(jìn)行繪圖,基本都是簡單的對(duì)Qt的一些常用類的使用,對(duì)面向?qū)ο蟮木幊虘?yīng)用的不是很好,更偏向于面向過程,所以完全可以改成C語言在Linux下實(shí)現(xiàn),思路都是相同的。
到此這篇關(guān)于QT實(shí)現(xiàn)貪吃蛇游戲代碼詳解的文章就介紹到這了,更多相關(guān)QT內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
VC外部符號(hào)錯(cuò)誤_main,_WinMain@16,__beginthreadex解決方法
這篇文章主要介紹了VC外部符號(hào)錯(cuò)誤_main,_WinMain@16,__beginthreadex解決方法,實(shí)例分析了比較典型的錯(cuò)誤及對(duì)應(yīng)的解決方法,需要的朋友可以參考下2015-05-05
C++調(diào)用libcurl開源庫實(shí)現(xiàn)郵件的發(fā)送功能流程詳解
libcurl是一個(gè)免費(fèi)開源的網(wǎng)絡(luò)傳輸庫,支持ftp、ftps、tftp,http、https、telnet、ldap、pop3、smtp等多種協(xié)議,接下來讓我們一起來了解吧2021-11-11
C++ 內(nèi)聯(lián)函數(shù)inline案例詳解
這篇文章主要介紹了C++ 內(nèi)聯(lián)函數(shù)inline案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-09-09
C語言實(shí)現(xiàn)輸入一個(gè)字符串后打印出該字符串中字符的所有排列
這篇文章主要介紹了C語言實(shí)現(xiàn)輸入一個(gè)字符串后打印出該字符串中字符的所有排列的方法,是數(shù)學(xué)中非常實(shí)用的排列算法,需要的朋友可以參考下2014-09-09
c語言詳解動(dòng)態(tài)內(nèi)存分配及常見錯(cuò)誤的解決
給數(shù)組分配多大的內(nèi)存空間?你是否和初學(xué)C時(shí)的我一樣,有過這樣的疑問。這一期就來聊一聊動(dòng)態(tài)內(nèi)存的分配,讀完這篇文章,你可能對(duì)內(nèi)存的分配有一個(gè)更好的理解2022-04-04

