俄罗斯方块 Tetris
今天,为大家带来一个用Qt C++ (Windows环境下)做的一个简易俄罗斯方块小游戏
思路和模块介绍都在注释里面,其次就是一些项目中遇到的问题以及解决方案,在后面部分说明。
一、效果
测试图样
Qt中文显示不容易啊~
二、代码
Tetris.pro
#-------------------------------------------------
#
# Project created by QtCreator --11T18::
#
#------------------------------------------------- QT += core gui greaterThan(QT_MAJOR_VERSION, ): QT += widgets TARGET = Tetris
TEMPLATE = app DEFINES += QT_DEPRECATED_WARNINGS SOURCES = main.cpp\
tetriswindow.cpp \
tetrisitem.cpp \
tetrisboard.cpp HEADERS = tetriswindow.h \
tetrisitem.h \
tetrisboard.h
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[][][]; //! [方块形状总坐标点列表]
ItemShape m_Shape; //! [方块的形状属性]
int coordinate[][]; //! [方块对应的坐标点列表] //! [Member-functions]
void resetX(const int Index, const int x){ coordinate[Index][] = x; }
void resetY(const int Index, const int y){ coordinate[Index][] = 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][]; }
const int get_y(const int Index) const { return coordinate[Index][]; }
const int get_most(const bool isMax = true, const bool x = true)const; //! [注释见下方]
//! [求取坐标最值,比如:最大x或最小的y坐标值等,4行代码就ok] }; #endif // TETRISITEM_H
tetrisitem.cpp
#include <QtCore>
#include "tetrisitem.h" const int TetrisItem::coordList[][][] =
{
{ { , }, { , }, { , }, { , } } //! [ NoShape ]
, { { , }, { , }, { , }, { , } } //! [ SquareShape ]
, { { , }, { , }, { , }, { , - } } //! [ LineShape]
, { { , }, { , }, { , }, { -, } }
, { { , - }, { -, - }, { -, }, { -, } } //! [ LShape ]
, { { , - }, { , - }, { , }, { , } }
, { { -, }, { -, - }, { , - }, { , - } }
, { { -, - }, { , - }, { , - }, { , } }
, { { -, - }, { -, }, { -, }, { , } }
, { { , }, { , }, { , }, { , - } }
, { { -, }, { -, }, { , }, { , } }
, { { -, }, { , }, { , }, { , } }
, { { , }, { , }, { , }, { , - } } //! [ ZShape ]
, { { , }, { , }, { -, }, { -, - } }
, { { -, }, { , }, { , }, { , } }
, { { -, }, { , }, { , }, { , } }
, { { -, }, { , }, { , }, { , } } //! [ TShape ]
, { { , }, { , }, { , }, { , - } }
, { { , }, { , }, { , - }, { -, } }
, { { , - }, { , }, { -, }, { , } }
}; //////////////////////////////////////////////
void TetrisItem::resetShape(const ItemShape& shape)
{
for(int i = ; i < ; ++i)
{
coordinate[i][] = coordList[shape][i][];
coordinate[i][] = coordList[shape][i][];
}
m_Shape = shape;
} //////////////////////////////////////////////
void TetrisItem::setRandomShape()
{
resetShape(ItemShape(qrand() % + ));
} //////////////////////////////////////////////
const TetrisItem TetrisItem::Rotate()const
{
if(m_Shape == SquareShape) //! [如果是田字方块,就无需旋转]
return*this; TetrisItem item(m_Shape);
for(int i = ; i < ; ++i)
{ //! [方块元素旋转90°]
item.resetX(i, get_y(i));
item.resetY(i, - * get_x(i));
}
return item;
} //////////////////////////////////////////////
const int TetrisItem::get_most(const bool IsMax, const bool x)const
{
int value = coordinate[][!x];
for(int i = ; i < ; ++i)
value = IsMax ? qMax(value, coordinate[i][!x]) : qMin(value, coordinate[i][!x]);
return value;
}
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_NAMESPACE class 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{ }, Board_H{ }; //! [面板的宽和高]
static const QColor colorList[]; //! [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 /( + 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 = );
void setNextItem_L(QLabel*); //! [设定标签,用于显示下一个方块的标签]
QPointer<QLabel> m_Pause_L; //! [显示暂停的Label] }; #endif // TETRISBOARD_H
tetrisboard.cpp
#include <QtWidgets>
#include "tetrisboard.h" const QColor TetrisBoard::colorList[] =
{
QColor(, , )
, QColor(, , )
, QColor( , , )
, QColor(, , )
, QColor(, , )
, QColor( , , )
}; //////////////////////////////////////////////
TetrisBoard::TetrisBoard(QWidget* parent)
:QFrame(parent) //! [构建基类]
, IsStart(false)
, IsPause(false)
, IsFall(false)
{
setLineWidth(); //! [边框设定参见QFrame类]
setMidLineWidth();
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(); //! [设定字体大小]
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 = ;
score = Item_Fall_num = Lines_moved_num = ;
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 = ; i < Board_H; ++i)
for(int j = ; j < Board_W; ++j)
{
ItemShape shape = Item_type(j, Board_H - i - );
if(shape != NoShape)
draw(painter, rect.left() + j * grid_W(), boardTop + i * grid_H(), shape);
} if(currentItem.get_Shpae() != NoShape)
for(int i = ; i < ; ++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 - ) * 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 - , currentY);
break;
case Qt::Key_Right:
case Qt::Key_D:
Move_(currentItem, currentX + , 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 = ; i < Board_H * Board_W; ++i)
m_board[i] = NoShape;
} //////////////////////////////////////////////
void TetrisBoard::Fall()
{
int fall_height = , y = currentY;
while(y > )
{
if(!Move_(currentItem, currentX, y - ))
break;
--y;
++fall_height;
}
Fall_after(fall_height);
} //////////////////////////////////////////////
void TetrisBoard::down()
{
if(!Move_(currentItem, currentX, currentY - ))
Fall_after();
} //////////////////////////////////////////////
void TetrisBoard::Fall_after(const int fall_height)
{
for(int i = ; i < ; ++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个提升一次等级]
{
++level;
m_timer.start(TimeOut(), this); //! [等级提升,刷新时间流逝速度]
emit level_change(level);
} score += fall_height + ;
emit score_change(score);
RemoveLine(); if(!IsFall)
newItem();
} //////////////////////////////////////////////
void TetrisBoard::RemoveLine()
{
int Num_remove = ;
for(int i = Board_H - ; i >= ; --i)
{
bool line_Is_Full = true; for(int j = ; 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 - ; ++k)
for(int j = ; j < Board_W; ++j)
Item_type(j, k) = Item_type(j, k + ); for(int L = ; L < Board_W; ++L)
Item_type(L, Board_H - ) = NoShape;
}
} if(Num_remove > )
{
Lines_moved_num += Num_remove;
score += * 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 / + ;
currentY = Board_H - + 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) + ;
int δy = nextItem.get_most(true, false) - nextItem.get_most(false, false) + ; QPixmap pixmap(δx * grid_W(), δy * grid_H());
QPainter painter(&pixmap);
painter.fillRect(pixmap.rect(), m_nextItem_L->palette().background()); for(int i = ; i < ; ++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 = ; i < ; ++i)
{
int x = X + item.get_x(i);
int y = Y - item.get_y(i);
if(x < || x >= Board_W || y < || 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( >= shape) color = colorList[shape];
else if( >= shape) color = colorList[];
else if( >= shape) color = colorList[];
else if( >= shape) color = colorList[];
else color = colorList[]; painter.fillRect(X + , Y + , grid_W() - , grid_H() - , color);
painter.setPen(color.light());
painter.drawLine(X, Y + grid_H() - , X, Y);
painter.drawLine(X, Y,X + grid_W() - , Y); painter.setPen(color.dark());
painter.drawLine(X + , Y + grid_H() - , X + grid_W() - , Y + grid_H() - );
painter.drawLine(X + grid_W() - , Y + grid_H() - , X + grid_W() - , Y + ); }
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_NAMESPACE class 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
tetriswindow.cpp
#include <QtWidgets> #include "tetriswindow.h"
#include "tetrisboard.h" TetrisWindow::TetrisWindow()
{
set_UserState(); board = new TetrisBoard; nextItem_L = new QLabel;
nextItem_L->setLineWidth(); //! [以下三行仍然是边框格式设置,参见QFrame类]
nextItem_L->setMidLineWidth();
nextItem_L->setFrameStyle(QFrame::Panel | QFrame::Sunken);
nextItem_L->setAlignment(Qt::AlignCenter);
board->setNextItem_L(nextItem_L); score_lcd = new QLCDNumber(); //! [设定初始LCD数字的位数]
level_lcd = new QLCDNumber();
line_lcd = new QLCDNumber(); 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")), , , , );
layout->addWidget(nextItem_L, , , , );
layout->addWidget(newLabel(tr("等级")),,,,);
layout->addWidget(level_lcd,,,,);
layout->addWidget(newLabel(tr("消失行数 ")), , , , );
layout->addWidget(line_lcd, , , , );
layout->addWidget(newLabel("TETRIS GAME"),,,,);
layout->addWidget(board, , , , );
layout->addWidget(board->m_Pause_L, , , , );
layout->addWidget(user_State, , , , );
layout->addWidget(newLabel(tr("分数")), , , , );
layout->addWidget(score_lcd, , , , );
layout->addWidget(start_btn, , );
layout->addWidget(pause_btn, , );
layout->addWidget(restart_btn, , );
layout->addWidget(quit_btn, , );
setLayout(layout); setWindowTitle("Tetris_Lv.");
resize(,);
} 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;
}
main.cpp
#include <QtWidgets> #include "tetriswindow.h" int main(int argc, char *argv[])
{
QApplication app(argc, argv);
TetrisWindow w;
w.show();
return app.exec();
}
三、过程中的一些问题
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() % + ;
}
如果该函数没有被其他的cpp文件调用,那么这个是没问题的。
但是,如果被其他的cpp函数调用了该内联函数,就会出现无法解析的外部符号。
那么该怎么验证这个呢,那我们俄罗斯方块的一个类中的内联函数来做一个测试
此时如果要inline关键字类外实现内联必须声明在对应的.h文件中才行,要么就去掉inline关键字
该项目工程中遇到的问题大概就这么多了。
谢谢您的阅读,生活愉快~
俄罗斯方块 Tetris的更多相关文章
- Java课设--俄罗斯方块Tetris
Java程序设计课程作业报告 作业:俄罗斯方块游戏 姓名 赵璐媛 学号 程序得分 90% 作业报告 得分10% 实验总分 100% 作业目的: 掌握基本的图形程序设计方法 掌握Java事件处理程序编写 ...
- 用C++实现俄罗斯方块(Tetris)游戏
我是一个C++初学者,控制台实现了一个俄罗斯方块游戏. 代码如下: //"俄罗斯方块"V1.0 //李国良于2017年1月20日编写完成 #include <iostream ...
- HDU1760 A New Tetris Game NP态
A New Tetris Game Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others ...
- A New Tetris Game
时间限制(普通/Java):1000MS/10000MS 运行内存限制:65536KByte 总提交: 40 测试通过: 12 描述 曾经,Lele和他姐姐最喜欢,玩得最 ...
- HDU-1760 A New Tetris Game DFS
曾经,Lele和他姐姐最喜欢,玩得最久的游戏就是俄罗斯方块(Tetris)了. 渐渐得,Lele发觉,玩这个游戏只需要手快而已,几乎不用经过大脑思考. 所以,Lele想出一个新的玩法. Lele和姐姐 ...
- hdu 1760 一道搜索博弈题 挺新颖的题目
A New Tetris Game Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others ...
- hdu1760博弈SG
A New Tetris Game Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others ...
- Python菜鸟快乐游戏编程_pygame(1)
Python菜鸟快乐游戏编程_pygame(博主录制,2K分辨率,超高清) https://study.163.com/course/courseMain.htm?courseId=100618802 ...
- FC红白机游戏列表(维基百科)
1055个fc游戏列表 日文名 中文译名 英文版名 发行日期 发行商 ドンキーコング 大金刚 Donkey Kong 1983年7月15日 任天堂 ドンキーコングJR. 大金刚Jr. Donkey K ...
随机推荐
- 【BearChild】
\(≧▽≦)/ BearChild is salty. If you want to save him,please call QQ:423339833 to talk♂with him. Have ...
- 博主退役了qwq
noip靠太差的(蒟蒻)博主退役了qwq 感觉以后都没什么机会可以继续写博客了 这个博客八成是坟了呀qwq 其实感觉也没有什么人关注qwq 所以也不长篇大论些什么了 就这样吧qwq
- 【专题】平衡树(Treap,fhq-treap)
[旋转] 平衡树中的旋转是指在不改变中序遍历的前提下改变树的形态的方式.(中序遍历=排名顺序) 右旋将当前点的左节点旋上来,左旋反之.(图侵删) void rturn(int &k){ int ...
- kafka入门(2)- 环境部署
部署Zookeeper(单机/集群) 1.下载安装文件: http://mirror.bit.edu.cn/apache/zookeeper/ 2.解压文件(本文解压到 D:\zookeeper-3. ...
- 解决Maven并行编译中出现打包错误问题的思路
解决Maven并行编译中出现打包错误问题的思路 并行构建 Maven 3.x 提供了并行编译的能力,通过执行下列命令就可以利用构建服务器的多线程/多核性能提升构建速度: mvn -T 4 clean ...
- oracle同义词是什么意思?
相当于alias,比如把user1.table1 在user2中建一个同义词table1create synonym table1 for user1.table1;这样当我们在user2中查sele ...
- 做了这么久的 DBA,你真的认识 MySQL 数据安全体系?【转】
给大家分享下有关MySQL在数据安全的话题,怎么通过一些配置来保证数据安全以及保证数据的存储落地是安全的. 我是在2014年加入陌陌,2015年加入去哪儿网,做MySQL的运维,包括自动化的开发. 接 ...
- C# 链接webservice报错
未处理 System.ServiceModel.EndpointNotFoundException Message="没有终结点对可能接受消息的 http://192.168.0.168/ ...
- 08 Packages 包
Packages Standard library Other packages Sub-repositories Community Standard library Name Synopsis ...
- 关于UrlEncode 一团乱麻的问题,后续彻底理解。Java中的 URLEncoder 与 URLDecoder无bug
很多开放平台都是小白开发的,对这个urlencode理解的不到位,他们总是认为java官方的urlencode有bug,需要 URLEncoder.encode("Hello World&q ...