今天,为大家带来一个用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相关推荐

  1. 俄罗斯方块Tetris(C基础,Linux终端)

    文章目录 俄罗斯方块Tetris(C基础,Linux终端) 前言 游戏说明 游戏效果展示 游戏程序实现步骤 一.准备工作 1.非阻塞型输入 2.在屏幕上打印一个方块 二.头文件.宏定义.全局变量.声明 ...

  2. python pygame 游戏实践: 俄罗斯方块(Tetris Game)第一步

    正在学习俄罗斯方块(Tetris Game)游戏, 主要参考Tetris with PyGame | Python Assets,不过有所修改,原作的class 太复杂, 不好理解, 试图用自己习惯的 ...

  3. 俄罗斯方块(Tetris)

    <俄罗斯方块>(Tetris, 俄文:Тетрис)是一款由俄罗斯人阿列克谢·帕基特诺夫于1984年6月发明的休闲游戏. 我将其作为我课程设计的题目,重温程序设计的基础.由于课设时间有限, ...

  4. 【Unity】简易俄罗斯方块(Tetris)制作

    原视频:https://www.youtube.com/watch?v=T5P8ohdxDjo b站转载:[UNITY]13分钟制作出俄罗斯方块!(附下载)_哔哩哔哩_bilibili 一.背景及方块 ...

  5. 500行代码写一个俄罗斯方块游戏

    导读:本文我们要制作一个俄罗斯方块游戏. 01 俄罗斯方块 Tetris 俄罗斯方块游戏是世界上最流行的游戏之一.是由一名叫Alexey Pajitnov的俄罗斯程序员在1985年制作的,从那时起,这 ...

  6. 500 行代码写一个俄罗斯方块游戏

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 导读:本文我们要制作一个俄罗斯方块游戏. 作者 | 派森 ...

  7. java程序里繁体字显示为方块_网页 俄罗斯方块

    游戏地址: 俄罗斯方块 | Tetris​zhangxiaoleiwk.gitee.io 看着眼熟?没错,UI 模仿了tetr.js,但代码是自己写的. 只支持电脑端,不知道键位可以点击设置查看. 游 ...

  8. 一个简易的游戏代码_500 行代码写一个俄罗斯方块游戏

    01 俄罗斯方块 Tetris 俄罗斯方块游戏是世界上最流行的游戏之一.是由一名叫Alexey Pajitnov的俄罗斯程序员在1985年制作的,从那时起,这个游戏就风靡了各个游戏平台. 俄罗斯方块归 ...

  9. js版俄罗斯方块(二)

    之前曾发过一个js版的俄罗斯方块,界面比较简单,Bug也不少.抽空重构了一下,加入了javaScript面向对象的知识,修复了一些明显的BUG. 斌斌 (给我写信) 原创博文(http://blog. ...

最新文章

  1. openstack mysql 故障_Openstack mysql自发连接错误2006,“mysql服务器已经离开
  2. boost::hana::make_tuple用法的测试程序
  3. Spring循环依赖的三种方式,你都清楚吗?
  4. shell 脚本比较字符串相等_LINUX快速入门第十六章:Shell 流程控制
  5. srpm包的编译方式
  6. java css路径_java web开发中CSS路径有问题吗,运行jsp文件为什么找不到css文件?...
  7. pdf照片显示正常打印时被翻转_明天开始打印准考证,你需要注意这些!
  8. ios mysql 创建不同的用户表_移动端iOS系统数据库之Realm(二)表的创建增删改查(多表)...
  9. java 方法注释_Java注释,java方法注释详解
  10. 软件版本中的release,stable,alpha,beta,pre,snapshot
  11. 免费WEB打印控件(插件)——打天下
  12. 前端 - base64原理浅析
  13. c语言编程师,单片机C语言编程师
  14. 生成一个6位数的随机密码,且需要包括字符、数字、特殊符号
  15. 1000x计算机 案例解析,索尼WI-1000X耳机连接win7电脑的步骤讲解
  16. Java及依赖和Maven
  17. 鸿蒙开发工具在哪下载,【鸿蒙开发工具下载】华为鸿蒙开发工具软件下载 v2.1.8 最新版-七喜软件园...
  18. C语言 水仙花数两种算法
  19. 比 ping 强大百倍的可视化工具!结果一目了然
  20. 思科三层交换机开启ipv6路由功能_思科路由器配置 IPv6 和 OSPFv3 路由

热门文章

  1. docker mysql镜像连接不上_还在手动安装应用?试一下Docker
  2. 项目中使用粘性布局不起作用_项目中的 Git 使用规范
  3. API数据安全知多少【知识篇】
  4. IIS请求筛选模块被配置为拒绝超过请求内容长度的请求
  5. 64位环境0和NULL的区别
  6. IDEA下用SBT搭建Spark Helloworld
  7. Maven内置属性及使用
  8. java Concurrent包学习笔记(一):ExecutorService
  9. Vue响应式数据: Observer模块实现
  10. Unity 3D观察者设计模式-C#委托和事件的运用