widget.h中的代碼
1 #ifndef WIDGET_H 2 #define WIDGET_H 3 #include <QWidget> 4 #include <QKeyEvent> 5 #include <QRectF> 6 #include <QPainter> 7 #include <QPen> 8 #include <QBrush> 9 #include <QDebug> 10 #include <QTimer> 11 #include <QTime> 12 #include <QDebug> 13 #include <QTime> 14 #include <QPaintEvent> 15 #include <QTimerEvent> 16 #include <QIcon> 17 #include <QPushButton> 18 #include <QVBoxLayout> 19 #include <QHBoxLayout> 20 #include <QPalette> 21 class Widget : public QWidget 22 { 23 Q_OBJECT 24 public: 25 Widget(QWidget *parent = nullptr); 26 ~Widget(); 27 //char moveFlag = 'U';//定義初始方向 28 void deleteAllitemsOfLayout(QLayout* layout);//刪除布局 29 protected: 30 void paintEvent(QPaintEvent *event); 31 void timerEvent(QTimerEvent *event); 32 void keyPressEvent(QKeyEvent *event); 33 private: 34 void moveLeft();//向左移動 35 void moveRight();//向右移動 36 void moveUp();//向上移動 37 void moveDown();//向下移動 38 void deleteLastRectF();//刪除最后一個節點 39 void iseatFood();//吃到了食物 40 bool isGameover();//是否結束游戲 41 protected slots: 42 void food();//生成食物 43 void pb_Start();//開始游戲 44 void pb_Quit();//退出游戲 45 private: 46 int snake_long = 4;//初始長度 47 QList<int> snake_x;//定義一個int類型的數據 x軸 48 QList<int> snake_y;//定義一個int類型的數據 y軸 49 int snake_size = 10;//定義單個身體大小 50 char moveFlag = 'U';//定義初始方向 51 QList<int> food_x;//食物 52 QList<int> food_y;//食物 53 int food_t = 0;//設置生成食物的時間 54 int timestop = 0; 55 int timerid; 56 //QTimer *foodTimer; 57 int gameover = 0; 58 private: 59 QPushButton *pb_start, *pb_quit; 60 }; 61 #endif // WIDGET_H
游戲主要通過繪圖事件來實現,首先實現“開始游戲”和“退出游戲”,利用QPushBottom生成兩個按鈕,並且點擊會有相應的操作
1 Widget::Widget(QWidget *parent) 2 : QWidget(parent) 3 { 4 this->setWindowTitle("貪吃蛇"); 5 this->setWindowIcon(QIcon(":/pic/1.png")); 6 resize(500, 500);//設置窗口大小 7 setStyleSheet("QWidget{background:white}"); 8 for(int i = 0; i < snake_long; i++) 9 { 10 snake_x.append(250); 11 snake_y.append(400 + i * 10); 12 } 13 food();//生成一個食物 14 QFont font("方正舒體",20,QFont::ExtraLight, false); 15 pb_start = new QPushButton; 16 pb_start->setText("開始游戲"); 17 pb_start->setFixedSize(200, 80); 18 pb_start->setFont(font); 19 pb_start->setFlat(true); 20 pb_quit = new QPushButton; 21 pb_quit->setText("退出游戲"); 22 pb_quit->setFixedSize(200, 80); 23 pb_quit->setFont(font); 24 pb_quit->setFlat(true); 25 QHBoxLayout *hbox1 = new QHBoxLayout; 26 hbox1->addStretch(); 27 hbox1->addWidget(pb_start); 28 hbox1->addStretch(); 29 QHBoxLayout *hbox2 = new QHBoxLayout; 30 hbox2->addStretch(); 31 hbox2->addWidget(pb_quit); 32 hbox2->addStretch(); 33 \ 34 QVBoxLayout *vbox = new QVBoxLayout; 35 vbox->addStretch(); 36 vbox->addLayout(hbox1); 37 vbox->addStretch(); 38 vbox->addLayout(hbox2); 39 vbox->addStretch(); 40 setLayout(vbox); 41 connect(pb_start, SIGNAL(clicked(bool)), this, SLOT(pb_Start())); 42 connect(pb_quit, SIGNAL(clicked(bool)), this, SLOT(pb_Quit())); 43 }
因為就兩個按鈕,就隨便布了一個局,退出游戲最簡單,只需要this->close();即可
1 void Widget::pb_Quit() 2 { 3 this->close(); 4 }
開始游戲之后,需要刪除之前的layout布局,但是不太會,網上找的相關代碼,倒是實現了這個功能
1 void Widget::pb_Start()//開始游戲 2 { 3 deleteAllitemsOfLayout(this->layout());//刪除布局 4 timestop = 1;//進入游戲 5 }
刪除布局,即刪除控件函數
1 //清除控件 2 void Widget::deleteAllitemsOfLayout(QLayout *layout) 3 { 4 QLayoutItem *child; 5 while ((child = layout->takeAt(0)) != nullptr) 6 { 7 //setParent為NULL,防止刪除之后界面不消失 8 if(child->widget()) 9 { 10 child->widget()->setParent(nullptr); 11 }else if(child->layout()){ 12 deleteAllitemsOfLayout(child->layout()); 13 } 14 delete child; 15 } 16 }
然后先生成食物的坐標,坐標只需要生成一個點即可
1 //生成食物的坐標 2 void Widget::food() 3 { 4 food_x.append(qrand()%(this->width()/10) * 10);//生成食物的位置坐標 5 food_y.append(qrand()%(this->height()/10) * 10); 6 }
這里用了一個定時器的東西,通過反復繪圖實現蛇的運動,不知道這個uodate();有什么作用,哈哈哈,不太會
1 void Widget::timerEvent(QTimerEvent *event) 2 { 3 update(); 4 }
蛇的定義是通過鏈表來實現的,qt有現成的函數可以實現直接在第一個位置上添加和刪除某一個位置上的數據。在移動的時候就需要這種函數,添加第一個位置,然后刪除最后一個元素即可
1 void Widget::moveLeft()//左移 2 { 3 snake_x.insert(0, (snake_x[0] - 10 + 500)%500); 4 snake_y.insert(0, snake_y[0]);//長度會加一 5 deleteLastRectF(); 6 } 7 void Widget::moveRight()//右移 8 { 9 snake_x.insert(0, (snake_x[0] + 10 + 500)%500); 10 snake_y.insert(0, snake_y[0]);//長度會加一 11 deleteLastRectF(); 12 } 13 void Widget::moveUp()//上移 14 { 15 snake_x.insert(0, snake_x[0]); 16 snake_y.insert(0, (snake_y[0] - 10 + 500)%500);//長度會加一 17 deleteLastRectF(); 18 } 19 void Widget::moveDown()//下移 20 { 21 snake_x.insert(0, snake_x[0]); 22 snake_y.insert(0, (snake_y[0] + 10 + 500)%500);//長度會加一 23 deleteLastRectF(); 24 }
然后刪除結尾的數據
1 //刪除結尾數據 2 void Widget::deleteLastRectF() 3 { 4 snake_x.removeAt(snake_x.length() - 1);//刪除最后一個節點 5 snake_y.removeAt(snake_y.length() - 1); 6 }
這個游戲,我實現了穿牆,所以只有在吃到自己的時候,蛇才會死亡,然后游戲結束
1 //判斷是否游戲結束 2 bool Widget::isGameover() 3 { 4 for(int i=0; i<snake_x.length(); i++){ 5 for(int j=i+1; j<snake_x.length(); j++){ 6 if((snake_x.at(i) == snake_x.at(j)) && (snake_y.at(i) == snake_y.at(j))){ 7 return true; 8 } 9 } 10 } 11 return false; 12 }
是否遲到了食物也很簡單
1 //判斷是否吃到食物 2 void Widget::iseatFood() 3 { 4 for(int i = 0; i < food_x.length(); i++) 5 { 6 if((snake_x.at(0) == food_x.at(i)) && (snake_y.at(0) == food_y.at(i)))//如果吃到食物 7 { 8 food_x.removeAt(i); 9 food_y.removeAt(i); 10 snake_x.append(snake_x.last()); 11 snake_y.append(snake_y.last()); 12 break; 13 } 14 } 15 }
移動的時候,需要先判斷當斷蛇頭移動的方向,對應的,按了向上鍵之后,按向下鍵,向下鍵會屬於失效的狀態,按不動,定義一個moveFlag,移動的時候更改他的值即可
1 //移動事件 2 void Widget::keyPressEvent(QKeyEvent *event) 3 { 4 switch (event->key()) { 5 case Qt::Key_Up: 6 if(moveFlag != 'D') { 7 moveFlag = 'U'; 8 } 9 break; 10 case Qt::Key_Down: 11 if(moveFlag != 'U') { 12 moveFlag = 'D'; 13 } 14 break; 15 case Qt::Key_Right: 16 if(moveFlag != 'L') { 17 moveFlag = 'R'; 18 } 19 break; 20 case Qt::Key_Left: 21 if(moveFlag != 'R') { 22 moveFlag = 'L'; 23 } 24 break; 25 } 26 }
然后就是畫圖了,畫圖這里,定義畫家,畫筆,設置樣式顏色等等,然后就是邏輯問題,我定義了一個timestop判斷是否結束繪圖,timestop的初始值為0,不進行繪圖,開始游戲之后,更改timestop的值為1,開始繪圖。通過moveFlag的值來回去當前移動的方向,然后更愛鏈表中的數據,在后面即開始繪圖,畫出蛇,畫出食物,等等。最后當游戲結束的時候,將我定義的gameover設置為1,相當於最后一次繪圖,將蛇死亡之前的畫面中心繪制下來,顯現在屏幕上,然后游戲結束。
1 //畫圖 2 void Widget::paintEvent(QPaintEvent *event) 3 { 4 if(timestop == 1) 5 { 6 timerid = startTimer(100);//停0.1秒 7 //向某一方向一直移動 8 if(moveFlag == 'U') { 9 moveUp(); 10 } 11 else if(moveFlag == 'D') { 12 moveDown(); 13 } 14 else if(moveFlag == 'R') { 15 moveRight(); 16 } 17 else if(moveFlag == 'L') { 18 moveLeft(); 19 } 20 21 QPainter painter(this); 22 QPen pen; 23 painter.setPen(pen); 24 pen.setWidth(snake_size); 25 26 QBrush brs(Qt::green); 27 28 QFont font("方正舒體",12,QFont::ExtraLight,false); 29 painter.setFont(font); 30 painter.drawText(20,20,QString("當前得分:")+QString("%1").arg(snake_x.length()-4)); 31 32 painter.setBrush(brs); 33 painter.drawEllipse(snake_x.at(0)-2, snake_y.at(0)-2, snake_size+4, snake_size+4); 34 35 for (int i = 1; i < snake_x.length(); i++) {//畫出蛇的初始狀態 36 painter.setBrush(brs); 37 //painter.drawRect(snake_x.at(i), snake_y.at(i), snake_size, snake_size); 38 painter.drawEllipse(snake_x.at(i), snake_y.at(i), snake_size, snake_size); 39 } 40 41 food_t++; 42 if(food_t == 20)//2秒生成一次食物 43 { 44 food(); 45 food_t = 0; 46 } 47 for (int i = 0; i < food_x.length(); i++) {//畫出食物 48 painter.setBrush(QColor(255,0,0)); 49 painter.drawRect(food_x.at(i), food_y.at(i), snake_size, snake_size); 50 } 51 if(isGameover()) 52 { 53 timestop = 0; 54 killTimer(timerid); 55 gameover = 1; 56 } 57 iseatFood(); 58 } 59 if(gameover == 1)//打印畫面 60 { 61 QPainter painter(this); 62 QPen pen; 63 painter.setPen(pen); 64 pen.setWidth(snake_size); 65 QBrush brs(Qt::green); 66 67 QFont font("方正舒體",12,QFont::ExtraLight,false); 68 painter.setFont(font); 69 painter.drawText(20,20,QString("當前得分:")+QString("%1").arg(snake_x.length()-4)); 70 painter.setBrush(brs); 71 painter.drawEllipse(snake_x.at(0)-2, snake_y.at(0)-2, snake_size+4, snake_size+4); 72 for (int i = 1; i < snake_x.length(); i++) {//畫出蛇的初始狀態 73 painter.setBrush(brs); 74 //painter.drawRect(snake_x.at(i), snake_y.at(i), snake_size, snake_size); 75 painter.drawEllipse(snake_x.at(i), snake_y.at(i), snake_size, snake_size); 76 } 77 for (int i = 0; i < food_x.length(); i++) {//畫出食物 78 painter.setBrush(QColor(255,0,0)); 79 painter.drawRect(food_x.at(i), food_y.at(i), snake_size, snake_size); 80 } 81 QFont font1("方正舒體",30,QFont::ExtraLight,false); 82 painter.setFont(font1); 83 painter.drawText((this->width()-200)/2,(this->height()-30)/2,QString("GAME OVER!")); 84 } 85 }
游戲界面
進入游戲
游戲結束