俄罗斯方块 Tetris
?
今天,為大家帶來一個用Qt C++ (Windows環境下)做的一個簡易俄羅斯方塊小游戲
思路和模塊介紹都在注釋里面,其次就是一些項目中遇到的問題以及解決方案,在后面部分說明。
一、效果
測試圖樣
?
Qt中文顯示不容易啊~
?
二、代碼
Tetris.pro
#------------------------------------------------- # # Project created by QtCreator 2018-02-11T18:16:14 # #-------------------------------------------------QT += core guigreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsTARGET = Tetris TEMPLATE = appDEFINES += QT_DEPRECATED_WARNINGSSOURCES = main.cpp\tetriswindow.cpp \tetrisitem.cpp \tetrisboard.cppHEADERS = tetriswindow.h \tetrisitem.h \tetrisboard.h View Code?
tetrisitem.h
#ifndef TETRISITEM_H #define TETRISITEM_H/******************************************************* //! [ TertrisItem 類 ] //! [ 這個類主要是俄羅斯方塊的方塊元素類 設置方塊元素的一些屬性 ] //! [ 設置方塊的形狀 方塊的坐標 方塊的生成 方塊的旋轉等 ] //! [ 方塊元素坐標化 以便于之后做處理(定位、顯示、繪圖等) ] ********************************************************///! [總共是20種形狀,NoShape在內總共6大類,同類型的當然可以通過旋轉互相轉換] //! [但是為了讓初始掉落的時候每個種類的形狀都能概率性出現,還是把所有的形狀都列了出來] //! [在之后的繪圖等后續工作中還是按6大類進行處理的,只有這里需要細分一下]enum ItemShape {NoShape, SquareShape, Line1Shape, Line2Shape,L1Shape, L2Shape, L3Shape, L4Shape,L5Shape, L6Shape, L7Shape, L8Shape,Z1Shape, Z2Shape, Z3Shape, Z4Shape,T1Shape, T2Shape, T3Shape, T4Shape, };class TetrisItem { private://! [data-Member]static const int coordList[20][4][2]; //! [方塊形狀總坐標點列表]ItemShape m_Shape; //! [方塊的形狀屬性]int coordinate[4][2]; //! [方塊對應的坐標點列表]//! [Member-functions]void resetX(const int Index, const int x){ coordinate[Index][0] = x; }void resetY(const int Index, const int y){ coordinate[Index][1] = y; }public:explicit TetrisItem( const ItemShape& shape = NoShape ){ resetShape(shape); }//! [set-Shape-functions]void resetShape(const ItemShape&); //! [重置方塊屬性]void setRandomShape(); //! [生成隨機方塊]const TetrisItem Rotate()const; //! [方塊元素旋轉]//! [get-Data-functions]const ItemShape& get_Shpae() const { return m_Shape; }const int get_x(const int Index) const { return coordinate[Index][0]; }const int get_y(const int Index) const { return coordinate[Index][1]; }const int get_most(const bool isMax = true, const bool x = true)const; //! [注釋見下方]//! [求取坐標最值,比如:最大x或最小的y坐標值等,4行代碼就ok] };#endif // TETRISITEM_H View Code?
tetrisitem.cpp
#include <QtCore> #include "tetrisitem.h"const int TetrisItem::coordList[20][4][2] = {{ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } //! [ NoShape ] , { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } } //! [ SquareShape ] , { { 0, 2 }, { 0, 1 }, { 0, 0 }, { 0, -1 } } //! [ LineShape] , { { 2, 0 }, { 1, 0 }, { 0, 0 }, { -1, 0 } } , { { 0, -1 }, { -1, -1 }, { -1, 0 }, { -1, 1 } } //! [ LShape ] , { { 0, -1 }, { 1, -1 }, { 1, 0 }, { 1, 1 } } , { { -1, 0 }, { -1, -1 }, { 0, -1 }, { 1, -1 } } , { { -1, -1 }, { 0, -1 }, { 1, -1 }, { 1, 0 } } , { { -1, -1 }, { -1, 0 }, { -1, 1 }, { 0, 1 } } , { { 0, 1 }, { 1, 1 }, { 1, 0 }, { 1, -1 } } , { { -1, 1 }, { -1, 0 }, { 0, 1 }, { 1, 1 } } , { { -1, 1 }, { 0, 1 }, { 1, 1 }, { 1, 0 } } , { { 0, 1 }, { 0, 0 }, { 1, 0 }, { 1, -1 } } //! [ ZShape ] , { { 0, 1 }, { 0, 0 }, { -1, 0 }, { -1, -1 } } , { { -1, 1 }, { 0, 1 }, { 0, 0 }, { 1, 0 } } , { { -1, 0 }, { 0, 0 }, { 0, 1 }, { 1, 1 } } , { { -1, 0 }, { 0, 0 }, { 0, 1 }, { 1, 0 } } //! [ TShape ] , { { 0, 1 }, { 0, 0 }, { 1, 0 }, { 0, -1 } } , { { 1, 0 }, { 0, 0 }, { 0, -1 }, { -1, 0 } } , { { 0, -1 }, { 0, 0 }, { -1, 0 }, { 0, 1 } } };// void TetrisItem::resetShape(const ItemShape& shape) {for(int i = 0; i < 4; ++i){coordinate[i][0] = coordList[shape][i][0];coordinate[i][1] = coordList[shape][i][1];}m_Shape = shape; }// void TetrisItem::setRandomShape() {resetShape(ItemShape(qrand() % 19 + 1)); }// const TetrisItem TetrisItem::Rotate()const {if(m_Shape == SquareShape) //! [如果是田字方塊,就無需旋轉]return*this;TetrisItem item(m_Shape);for(int i = 0; i < 4; ++i){ //! [方塊元素旋轉90°] item.resetX(i, get_y(i));item.resetY(i, -1 * get_x(i));}return item; }// const int TetrisItem::get_most(const bool IsMax, const bool x)const {int value = coordinate[0][!x];for(int i = 1; i < 4; ++i)value = IsMax ? qMax(value, coordinate[i][!x]) : qMin(value, coordinate[i][!x]);return value; } View Code?
tetrisboard.h
#ifndef TETRISBOARD_H #define TETRISBOARD_H/****************************************** //! [ TetrisBoard 類 ] //! [ 面板類 設定面板相關的屬性 ] //! [ 面板上的事件響應設定 信號響應設定 ] //! [ 面板的繪圖 事件響應設定 方塊移動 等 ] //! [ 設定面板應該具有的一些數據 ] //! [難度等級的改變是隨著方塊的下降的數量而改變的] ******************************************/#include <QFrame> #include <QPointer> #include <QBasicTimer> #include "tetrisitem.h"QT_BEGIN_NAMESPACE class QLabel; class QFont; class QColor; QT_END_NAMESPACEclass TetrisBoard : public QFrame {Q_OBJECT//! [信號-槽] public slots:void SLOT_start(); //! [游戲開始設置]void SLOT_pause(); //! [游戲暫停設置]void SLOT_reset(); //! [重新開始設置] signals:void score_change(const int); //! [改變分數]void level_change(const int); //! [改變等級]void Remove_line_change(const int); //! [改變已消除行數]//! [信號-槽 END]private://! [Data-Member]static const int Board_W{ 10 }, Board_H{ 22 }; //! [面板的寬和高]static const QColor colorList[6]; //! [6類方塊的顏色列表]QBasicTimer m_timer; //! [ 計時器 ]QPointer<QLabel> m_nextItem_L; //! [QPointer模板類似智能指針]TetrisItem currentItem, nextItem; //! [當前方塊 下一個方塊]bool IsStart, IsPause; //! [暫停、開始 與否]bool IsFall; //! [是否已經落下]int currentX, currentY; //! [當前的x,y]int Lines_moved_num, Item_Fall_num; //! [消去的行數 下落的方塊數]int score, level; //! [分數 等級] ItemShape m_board[Board_W * Board_H]; //! [注釋見下方]//! [此為俄羅斯方塊活動的區域中每一個小格子所屬方塊類型的數組]//! [ Member-functions ] [ Inline-functions ]ItemShape& Item_type(const int x,const int y) //! [獲取(x,y)的方塊類型]{ return m_board[y * Board_W + x]; }const int TimeOut()const //! [設定計時器的流逝速度]{ return 1000/(1 + level); }const int grid_W()const //! [求劃分的一個小格子的寬]{ return contentsRect().width()/Board_W; } //! [con..ect()函數返回面板矩形]const int grid_H()const{ return contentsRect().height()/Board_H; }void clearBoard(); //! [清空面板(將所有小格子的方塊類型置0)]void Fall(); //! [瞬降]void down(); //! [下落]void RemoveLine(); //! [消除一行]void Fall_after(const int); //! [落定之后的數據更新]void newItem(); //! [構建下一個俄羅斯方塊]void showNext(); //! [展示下一個方塊]bool Move_(const TetrisItem&,const int,const int); //! [移動]void draw(QPainter&,const int,const int,const ItemShape&); //! [描繪小格子]protected: //! [三個事件]void paintEvent(QPaintEvent *)Q_DECL_OVERRIDE;void keyPressEvent(QKeyEvent*)Q_DECL_OVERRIDE;void timerEvent(QTimerEvent *)Q_DECL_OVERRIDE;public:TetrisBoard(QWidget* parent = 0);void setNextItem_L(QLabel*); //! [設定標簽,用于顯示下一個方塊的標簽]QPointer<QLabel> m_Pause_L; //! [顯示暫停的Label] };#endif // TETRISBOARD_H View Code?
tetrisboard.cpp
#include <QtWidgets> #include "tetrisboard.h"const QColor TetrisBoard::colorList[6] = {QColor(255, 255, 255) , QColor(128, 36, 221) , QColor( 56, 210, 40) , QColor(152, 165, 6) , QColor(223, 22, 22) , QColor( 37, 237, 244) };// TetrisBoard::TetrisBoard(QWidget* parent):QFrame(parent) //! [構建基類] , IsStart(false) , IsPause(false) , IsFall(false) {setLineWidth(2); //! [邊框設定參見QFrame類]setMidLineWidth(3);setFrameStyle(QFrame::Box | QFrame::Raised); //! [三個函數用于設定邊框]setFocusPolicy(Qt::StrongFocus); //! [設定焦點策略] clearBoard(); //! [清空游戲面板]nextItem.setRandomShape(); //! [隨機生成下一個方塊]//! [下面是暫停標簽的設置]m_Pause_L = new QLabel("Pause",this);m_Pause_L->setAlignment(Qt::AlignHCenter);QFont* font = new QFont; //! [創建文字]font->setPointSize(50); //! [設定字體大小]QPalette p; //! [調色板]p.setColor(QPalette::WindowText,Qt::red); //! [置調色板的顏色] m_Pause_L->setPalette(p); //! [設置標簽的調色和文字]m_Pause_L->setFont(*font);m_Pause_L->setVisible(false); //! [設置標簽可見性,暫停時可見] }// void TetrisBoard::setNextItem_L(QLabel* label) {m_nextItem_L = label; }// void TetrisBoard::SLOT_start() {if(IsPause||IsStart) return; //! [如果游戲已經開始或者暫停,則該按鈕無效] IsStart = true; //! [游戲開始時的狀態數據初始化]IsFall = false;level = 1;score = Item_Fall_num = Lines_moved_num = 0;clearBoard();//! [發射信號] emit Remove_line_change(Lines_moved_num);emit score_change(score);emit level_change(level);newItem(); //! [生成新的方塊]m_timer.start(TimeOut(),this); //! [時間重新開始,按照para1 毫秒的速度流逝] }// void TetrisBoard::SLOT_reset() //! [重新開始,需要將開始和暫停置為false,然后執行start] {IsStart = false;IsPause = false;SLOT_start(); }// void TetrisBoard::SLOT_pause() {if(!IsStart) return; //! [游戲未開始,無效] IsPause = !IsPause;if(IsPause){m_timer.stop();m_Pause_L->setVisible(true);}else{m_timer.start(TimeOut(),this);m_Pause_L->setVisible(false);}}// void TetrisBoard::paintEvent(QPaintEvent *event) {QFrame::paintEvent(event); //! [先調用基類的]QPainter painter(this); //! [繪圖類]QRect rect = contentsRect(); //! [矩形類,該函數在頭文件中已介紹過]int boardTop = rect.bottom() - Board_H * grid_H();for(int i = 0; i < Board_H; ++i)for(int j = 0; j < Board_W; ++j){ItemShape shape = Item_type(j, Board_H - i - 1);if(shape != NoShape)draw(painter, rect.left() + j * grid_W(), boardTop + i * grid_H(), shape);}if(currentItem.get_Shpae() != NoShape)for(int i = 0; i < 4; ++i){int x = currentX + currentItem.get_x(i);int y = currentY - currentItem.get_y(i);draw(painter, rect.left() + x * grid_W(),boardTop + (Board_H - y - 1) * grid_H(), currentItem.get_Shpae());} }// void TetrisBoard::keyPressEvent(QKeyEvent *event) {if(!IsStart || IsPause || currentItem.get_Shpae() == NoShape){QFrame::keyPressEvent(event);return;}switch(event->key()) //! [判別鍵盤按鍵] {case Qt::Key_Left:case Qt::Key_A:Move_(currentItem, currentX - 1, currentY);break;case Qt::Key_Right:case Qt::Key_D:Move_(currentItem, currentX + 1, currentY);break;case Qt::Key_Up:case Qt::Key_W:Move_(currentItem.Rotate(), currentX, currentY);break;case Qt::Key_Down:case Qt::Key_S:Fall();break;default:QFrame::keyPressEvent(event);} }// void TetrisBoard::timerEvent(QTimerEvent *event) {if(event->timerId() == m_timer.timerId()) //! [一個時間單位一個時間單位對應刷新相關的設置]if(IsFall) //! [如果某一時刻的方塊已經落下,那么重新生成一個] {IsFall = false;newItem();m_timer.start(TimeOut(),this);}else down();else QFrame::timerEvent(event); }// void TetrisBoard::clearBoard() {for(int i = 0; i < Board_H * Board_W; ++i)m_board[i] = NoShape; }// void TetrisBoard::Fall() {int fall_height = 0, y = currentY;while(y > 0){if(!Move_(currentItem, currentX, y - 1))break;--y;++fall_height;}Fall_after(fall_height); }// void TetrisBoard::down() {if(!Move_(currentItem, currentX, currentY - 1))Fall_after(0); }// void TetrisBoard::Fall_after(const int fall_height) {for(int i = 0; i < 4; ++i) //! [刷新面板上對應位置的方塊類型屬性] {int x = currentX + currentItem.get_x(i);int y = currentY - currentItem.get_y(i);Item_type(x, y) = currentItem.get_Shpae();}++Item_Fall_num;if(Item_Fall_num % 28 == 0) //! [如果沒28個提升一次等級] {++level;m_timer.start(TimeOut(), this); //! [等級提升,刷新時間流逝速度] emit level_change(level);}score += fall_height + 8;emit score_change(score);RemoveLine();if(!IsFall)newItem(); }// void TetrisBoard::RemoveLine() {int Num_remove = 0;for(int i = Board_H - 1; i >= 0; --i){bool line_Is_Full = true;for(int j = 0; j < Board_W; ++j)if(Item_type(j, i) == NoShape){line_Is_Full = false;break;}if(line_Is_Full){++Num_remove;for(int k = i; k < Board_H - 1; ++k)for(int j = 0; j < Board_W; ++j)Item_type(j, k) = Item_type(j, k + 1);for(int L = 0; L < Board_W; ++L)Item_type(L, Board_H - 1) = NoShape;}}if(Num_remove > 0){Lines_moved_num += Num_remove;score += 13 * Num_remove;emit Remove_line_change(Lines_moved_num);emit score_change(score);IsFall = true;currentItem.resetShape(NoShape);update();} }// void TetrisBoard::newItem() {currentItem = nextItem;nextItem.setRandomShape();showNext();currentX = Board_W / 2 + 1;currentY = Board_H - 1 + currentItem.get_most(false, false);if(!Move_(currentItem, currentX, currentY)){currentItem.resetShape(NoShape);m_timer.stop();IsStart = false;} }// void TetrisBoard::showNext() {if(!m_nextItem_L)return;int δx = nextItem.get_most(true, true) - nextItem.get_most(false, true) + 1;int δy = nextItem.get_most(true, false) - nextItem.get_most(false, false) + 1;QPixmap pixmap(δx * grid_W(), δy * grid_H());QPainter painter(&pixmap);painter.fillRect(pixmap.rect(), m_nextItem_L->palette().background());for(int i = 0; i < 4; ++i){int x = nextItem.get_x(i) - nextItem.get_most(false,true);int y = nextItem.get_y(i) - nextItem.get_most(false,false);draw(painter, x * grid_W(), y * grid_H(),nextItem.get_Shpae());}m_nextItem_L->setPixmap(pixmap); }// bool TetrisBoard::Move_(const TetrisItem& item, const int X, const int Y) {for(int i = 0; i < 4; ++i){int x = X + item.get_x(i);int y = Y - item.get_y(i);if(x < 0 || x >= Board_W || y < 0 || y >= Board_H) //! [超過邊界返回false]return false;if(Item_type(x, y) != NoShape) //! [如果下一個位置不為空,返回false]return false;}currentItem = item;currentX = X;currentY = Y;update();return true; }// void TetrisBoard::draw(QPainter& painter, const int X, const int Y, const ItemShape& shape) {QColor color;if(1 >= shape) color = colorList[shape];else if(3 >= shape) color = colorList[2];else if(11 >= shape) color = colorList[3];else if(15 >= shape) color = colorList[4];else color = colorList[5];painter.fillRect(X + 1, Y + 1, grid_W() - 2, grid_H() - 2, color);painter.setPen(color.light());painter.drawLine(X, Y + grid_H() - 1, X, Y);painter.drawLine(X, Y,X + grid_W() - 1, Y);painter.setPen(color.dark());painter.drawLine(X + 1, Y + grid_H() - 1, X + grid_W() - 1, Y + grid_H() - 1);painter.drawLine(X + grid_W() - 1, Y + grid_H() - 1, X + grid_W() - 1, Y + 1);} View Code?
tetriswindow.h
#ifndef TETRISWINDOW_H #define TETRISWINDOW_H/************************************** //! [ TetrisWindow 類 ] //! [ 窗口顯示控制 ] //! [ 設置布局 信號-槽響應設定 LCD顯示 等 ] ***************************************/#include <QWidget>QT_BEGIN_NAMESPACE class QFrame; class QString; class QLCDNumber; class QLabel; class QPushButton; class TetrisBoard; QT_END_NAMESPACEclass TetrisWindow : public QWidget {Q_OBJECT private:QLabel* newLabel(const QString&); //! [創建標簽] QLabel* user_State; //! [使用說明]TetrisBoard* board;QLabel* nextItem_L;QLCDNumber* score_lcd, *level_lcd, *line_lcd; //! [LCD數字顯示數據]QPushButton* start_btn, *restart_btn, *quit_btn, *pause_btn;public:TetrisWindow();void set_UserState();};#endif // TETRISWINDOW_H View Code?
tetriswindow.cpp
#include <QtWidgets>#include "tetriswindow.h" #include "tetrisboard.h"TetrisWindow::TetrisWindow() {set_UserState();board = new TetrisBoard;nextItem_L = new QLabel;nextItem_L->setLineWidth(3); //! [以下三行仍然是邊框格式設置,參見QFrame類]nextItem_L->setMidLineWidth(2);nextItem_L->setFrameStyle(QFrame::Panel | QFrame::Sunken);nextItem_L->setAlignment(Qt::AlignCenter);board->setNextItem_L(nextItem_L);score_lcd = new QLCDNumber(5); //! [設定初始LCD數字的位數]level_lcd = new QLCDNumber(2);line_lcd = new QLCDNumber(3);score_lcd->setSegmentStyle(QLCDNumber::Flat);level_lcd->setSegmentStyle(QLCDNumber::Filled);line_lcd->setSegmentStyle(QLCDNumber::Filled);start_btn = new QPushButton(tr("Start"));restart_btn = new QPushButton(tr("Restart"));pause_btn = new QPushButton(tr("Pause"));quit_btn = new QPushButton(tr("Quit"));//! [按鈕的焦點策略設定為無,不然的話點擊開始,按方向鍵只會使焦點在各個按鈕之間流動,而不是進行操作]start_btn->setFocusPolicy(Qt::NoFocus);restart_btn->setFocusPolicy(Qt::NoFocus);pause_btn->setFocusPolicy(Qt::NoFocus);quit_btn->setFocusPolicy(Qt::NoFocus);//! [信號-槽] connect(start_btn, SIGNAL(clicked()), board, SLOT(SLOT_start()));connect(restart_btn, SIGNAL(clicked()), board, SLOT(SLOT_reset()));connect(pause_btn, SIGNAL(clicked()),board,SLOT(SLOT_pause()));connect(quit_btn, SIGNAL(clicked()), qApp, SLOT(quit()));connect(board, SIGNAL(score_change(int)),score_lcd, SLOT(display(int)));connect(board, SIGNAL(level_change(int)),level_lcd, SLOT(display(int)));connect(board, SIGNAL(Remove_line_change(int)),line_lcd, SLOT(display(int)));//! [布局]QGridLayout* layout = new QGridLayout;layout->addWidget(newLabel(tr("Next")), 0, 0, 1, 2);layout->addWidget(nextItem_L, 1, 0, 2, 2);layout->addWidget(newLabel(tr("等級")),3,0,1,2);layout->addWidget(level_lcd,4,0,2,2);layout->addWidget(newLabel(tr("消失行數 ")), 6, 0, 1, 2);layout->addWidget(line_lcd, 7, 0, 2, 2);layout->addWidget(newLabel("TETRIS GAME"),0,2,1,2);layout->addWidget(board, 1, 2, 8, 2);layout->addWidget(board->m_Pause_L, 4, 2, 1, 2);layout->addWidget(user_State, 0, 4, 4, 2);layout->addWidget(newLabel(tr("分數")), 3, 4, 1, 2);layout->addWidget(score_lcd, 4, 4, 2, 2);layout->addWidget(start_btn, 7, 4);layout->addWidget(pause_btn, 7, 5);layout->addWidget(restart_btn, 8, 4);layout->addWidget(quit_btn, 8, 5);setLayout(layout);setWindowTitle("Tetris_Lv.");resize(700,450); }void TetrisWindow::set_UserState() {QString State = tr("\n#···· 游戲使用說明 ····#\n\n#·方向鍵Up/W: 變換形狀 \\**/\n\n#·方向鍵Down/S: 瞬降 \\**/\n\n#·方向鍵Left/A: 左移,長按加速\**/\n\n#·方向鍵Right/D:右移,長按加速\**/");user_State = new QLabel(State);user_State->setAlignment(Qt::AlignLeft); //! [左對齊] }QLabel* TetrisWindow::newLabel(const QString & label) {QLabel* lab = new QLabel(label);lab->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);return lab; } View Code?
main.cpp
#include <QtWidgets>#include "tetriswindow.h"int main(int argc, char *argv[]) {QApplication app(argc, argv);TetrisWindow w;w.show();return app.exec(); } View Code?
三、過程中的一些問題
1)中文注釋的問題
Qt的中文注釋有時候會引發編譯錯誤,有時即使編譯通過了,執行的時候也會出現一些預料之外的結果,這時候,如果代碼邏輯沒有問題,那就得考慮是否是中文注釋引發的。
最近終于找到一種注釋中文的“官方”形式, 即 ?//! [ ] ?,我這樣寫沒有出現什么異樣。
?
2)error LNK2001
采用 信號-槽 機制的時候,signals信號函數是只有聲明,信號由moc自動產生,是無需cpp實現的,必須加上Q_OBJECT宏定義,如下: ?
?
?不然信號函數名會成為無法解析的外部符號 ? error LNK 2019
這屬于鏈接錯誤,沒有生成對應的moc文件:比如上述,就沒有生成tetrisboard相關的moc文件
鏈接正確,構建后會生成生成對應的moc文件:
?
出現這種錯誤還可能因為后面新加了一些信號-槽等
解決方案:
1> 將文件中的Debug文件刪除,重新構建。
2>創一個新的.h和.cpp文件,復制原來內容,將原來的文件從工程中刪掉,重新構建(編譯)
3>重新創建工程
了解到的就這些了。
?
3)inline關鍵字會導致無法解析的外部符號??
類中的內聯函數在類外定義需要加上inline關鍵字,但是Qt 中會出現錯誤??
我們來看一下下面這個代碼:
class TetrisItem { private:int m_shape; public:void setRandomShape(); };上面是頭文件的類聲明
我們在對應的cpp中實現內聯函數
inline void TetrisItems::setRandomShape() {m_shape = qrand() % 19 + 1; }如果該函數沒有被其他的cpp文件調用,那么這個是沒問題的。
但是,如果被其他的cpp函數調用了該內聯函數,就會出現無法解析的外部符號。
那么該怎么驗證這個呢,那我們俄羅斯方塊的一個類中的內聯函數來做一個測試
?
此時如果要inline關鍵字類外實現內聯必須聲明在對應的.h文件中才行,要么就去掉inline關鍵字
?
該項目工程中遇到的問題大概就這么多了。
?
謝謝您的閱讀,生活愉快~
轉載于:https://www.cnblogs.com/lv-anchoret/p/8446828.html
總結
以上是生活随笔為你收集整理的俄罗斯方块 Tetris的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2018.2月
- 下一篇: 记linux_centOS安装as86过