当前位置:文档之家› 关于俄罗斯方块的嵌入式设计报告

关于俄罗斯方块的嵌入式设计报告

摘要Qt是一个跨平台的C++图形用户界面应用程序框架。

本程序利用Qt提供的相关类,实现了俄罗斯方块的基本功能。

关键字:QT、嵌入式、软件开发一.功能说明✧支持俄罗斯方块游戏的基本功能✧支持虚拟按键二.开发环境操作系统:ubuntu 10.04 LTS;开发工具:gnu编译工具链(gcc等)、Qt Creator、Qt 4.6.2。

2.1 Qt简介Qt是跨平台的应用程序和UI框架。

它包括跨平台类库、集成开发工具和跨平台IDE。

使用Qt,只需一次性开发应用程序,无须重新编写源代码,便可跨不同桌面和嵌入式操作系统部署这些应用程序。

2.2Qt开发基础2.2.1Qt对象与对象树QObject是所有Qt类的基类。

QObject 组织成为对象树。

当你创建QObject 时,将另外的对象作为其父对象,这个对象就被加入其父对象的children() 列表,并且当父对象销毁时,这个对象也能够被销毁。

事实证明,这种实现方法非常适合GUI 对象。

例如,一个QShortcut(键盘快捷键)对象是相关窗口的子对象,所以当用户关闭窗口时,这个对象也能够被删除。

QWidget 作为所有能够显示在屏幕上的组件的父类,扩展了这种父子关系。

一个子对象通常也成为一个子组件,就是说,它被显示在父组件的坐标系统中,受到父组件的边界影响可能会有剪切等等。

例如,当应用程序销毁掉已关闭的消息对话框时,对话框上面的按钮和标签一起被销毁,就像我们希望的那样,因为这些按钮和标签都是对话框的子对象。

2.2.2信号与槽在GUI 编程中,当我们改变了一个组件,我们经常需要通知另外的一个组件。

更一般地,我们希望任何类型的对象都能够与另外的对象通讯。

例如,如果用户点击了关闭按钮,我们希望窗口的close() 函数被调用。

早期工具库对这种通讯使用回调实现。

回调是一个指向一个函数的指针,所以如果你希望某种事件发生的时候,处理函数获得通知,你就需要将指向另外函数的指针(也就是这个回调)传递给处理函数。

这样,处理函数就会在合适的时候调用回调函数。

回调有两个明显的缺点:第一,它们不是类型安全的。

我们不能保证处理函数传递给回调函数的参数都是正确的。

第二,回调函数和处理函数紧密地耦合在一起,因为处理函数必须知道哪一个函数被回调。

在Qt 中,我们有回调技术之外的选择:信号槽。

当特定事件发出时,一个信号会被发出。

Qt 组件有很多预定义的信号,同时,我们也可以通过继承这些组件,添加自定义的信号。

槽则能够响应特定信号的函数。

Qt 组件有很多预定义的槽,但是更常见的是,通过继承组件添加你自己的槽,以便你能够按照自己的方式处理信号。

信号槽机制是类型安全的:信号的签名必须同接受该信号的槽的签名一致(实际上,槽的参数个数可以比信号少,因为槽能够忽略信号定义的多出来的参数)。

既然签名都是兼容的,那么编译器就可以帮助我们找出不匹配的地方。

信号和槽是松耦合的:发出信号的类不知道也不关心哪些槽连接到它的信号。

Qt 的信号槽机制保证了,如果你把一个信号同一个槽连接,那么在正确的时间,槽能够接收到信号的参数并且被调用。

信号和槽都可以有任意类型的任意个数的参数。

它们全部都是类型安全的。

所有继承自QObject 或者它的一个子类(例如QWidget)都可以包含信号槽。

信号在对象改变其状态,并且这个状态可能有别的对象关心时被发出。

这就是这个对象为和别的对象交互所做的所有工作。

它并不知道也不关心有没有别的对象正在接收它发出的信号。

这是真正的信息封装,保证了这个对象能够成为一个组件。

槽能够被用于接收信号,也能够像普通函数一样使用。

正如一个对象并不知道究竟有没有别的对象正在接收它的信号一样,一个槽也不知道有没有信号与它相连。

这保证了使用Qt 可以创建真正相互独立的组件。

你可以将任意多个信号连接到同一个槽上,也可能将一个信号连接任意多个槽。

同时,也能够直接将一个信号与另一个信号相连(这会使第一个信号发出时,马上发出第二个信号)。

总之,信号槽建立起一种非常强大的组件编程机制。

2.2.3事件在Qt中,事件是作为对象处理的,所有事件对象继承自抽象类QEvent。

此类用来表示程序内部发生或者来自于外部但应用程序应该知道的动作。

事件能够能过被QObject 的子类接受或者处理,但是通常用在与组件有关的应用中。

本文档主要阐述了在一个典型应用中的事件接收与处理。

当一个事件产生时,Qt 通过实例化一个QEvent 的合适的子类来表示它,然后通过调用event() 函数发送给QObject 的实例(或者它的子类)。

event() 函数本身并不会处理事件,根据事件类型,它将调用相应的事件处理函数,并且返回事件被接受还是被忽略。

一些事件,比如QMouseEvent 和QKeyEvent,来自窗口系统;有的,比如QTimerEvent,来自于其他事件源;另外一些则来自应用程序本身。

通常事件的处理需要调用一个虚函数。

比如,QPaintEvent 事件的处理需要调用QWidget::paintEvent() 函数。

这个虚函数负责做出适当的响应,通常是用来重绘组件。

如果你在自己的函数中并不打算实现所有的处理,你可以调用基类的实现。

三.系统设计3.1需求分析⏹可随机生成7种基本方块单元⏹不同的方块单元具备不同的颜色⏹基本方块单元在移动时支持两种操作:旋转、移动⏹具备计分及升级系统⏹支持虚拟按键3.2框架设计3.2.1俄罗斯方块基本规则一个用于摆放小型正方形的平面虚拟场地,其标准大小:行宽为10,列高为20,以每个小正方形为单位。

一组由4个小型正方形组成的规则图形,英文称为Tetromino,中文通称为方块共有7种,分别以S、Z、L、J、I、O、T这7个字母的形状来命名。

随机发生器不断地输出单个方块到场地顶部,以一定的规则进行移动、旋转、下落和摆放,锁定并填充到场地中。

每次摆放如果将场地的一行或多行完全填满,则组成这些行的所有小正方形将被消除,并且以此来换取一定的积分或者其他形式的奖励。

而未被消除的方块会一直累积,并对后来的方块摆放造成各种影响。

如果未被消除的方块堆放的高度超过场地所规定的最大高度(并不一定是20或者玩家所能见到的高度),则游戏结束。

3.2.2系统模块如上图所示,系统可由以下几个模块组成:虚拟显示屏:为系统核心模块,负责游戏元素的显示、游戏逻辑的执行、以及游戏状态的维护、接收操作模块的操作信息、为辅助显示模块提供必要的信息辅助显示模块:显示下一个方块单元的类型、当前分数、当前等级操作区模块:为用户提供操作按键四.系统实现系统源文件布局如下:✧HTetris.pro:系统工程文件✧HTetrisWindow.h:HTetrisWindow类声明头文件✧HTetrisPiece.h:HTetrisPiece类声明头文件✧HTetrisBoard.h:HTetrisBoard类声明头文件✧tetris.qrc:系统资源文件,存放了表示方向的图像数据✧HTetrisWindow.cpp:HTetrisWindow类的实现✧HTetrisPiece.cpp:HTetrisPiece类的实现✧HTetrisBoard.cpp:HTetrisBoard类的实现✧main.cpp:程序入口main.cpp中初始化一个HTetrisWindow实例,并使其显示。

HTetrisWindow对应程序窗口,它包含一个游戏显示区(HTetrisBoard)、辅助显示区、及一些按键,HTetrisWindow在自身的构造函数中完成对这些界面元素的初始化及布局工作,同时建立起必要的信号-槽连接。

HTetrisPiece类表示基本方块单元,总共有7种,即I、T、J、L、O、Z、S,用HTetrisPieceShape来标识方块类型。

HTetrisPiece提供了设置方块形状、设置旋转、获取方块信息的一些公共成员函数。

HTetrisPiece使用coords[4][2]这个二维数组来存储方块的形状信息,这个数组的每行表示一个点的坐标。

HTetrisBoard是整个程序的核心,相对前两个类,这个类要复杂很多。

它提供了如下几个槽:start()、pause()、moveRight()、moveLeft()、moveDown()、rotateRight()、rotateLeft()。

提供了scoreChanged与levelChanged两个信号。

paintEvent负责整个HTetrisBoard的重绘。

removeFullLines负责判断是否某行全部为方块,如果是,则把该行消除,同时添加一定分数及经验。

五.系统测试程序的运行界面如上图所示,经测试,该程序具备了俄罗斯方块游戏的基本功能。

五.小结通过这次嵌入式实验,我对嵌入式技术有了更加深入的了解,在老师悉心帮助下,和其他同学的共同努力下,我们最终圆满地完成了这次课程设计。

但是实验中,也暴露了自己在软件运用方面的不足和缺点,以后在这方面上认真学习和研究,争取在毕业之前能更上一层楼。

六.附录6.1参考资料[1]/4.6/[2]C plus plus GUI Programming with Qt 4 2nd Edition[3]6.2程序源码/**Filename: main.cpp*Author: Hale Chan <halechan@>*Date: 2011-11-24*/#include <QtGui>#include "HTetrisWindow.h"int main(int argc, char *argv[]){QApplication app(argc, argv);HTetrisWindow window;window.show();qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));return app.exec();}/**Filename: HTetrisWindow.h*Author: Hale Chan <halechan@>*Date: 2011-11-24*/#ifndef HTetrisWINDOW_H#define HTetrisWINDOW_H#include <QWidget>class HTetrisBoard;class QLabel;class QLCDNumber;class QPushButton;class HTetrisWindow : public QWidget{Q_OBJECTpublic:HTetrisWindow();private:QLabel *createLabel(const QString &text);HTetrisBoard *board;QLabel *nextPieceLabel;QLCDNumber *scoreLcd;QLCDNumber *levelLcd;QPushButton *leftButton;QPushButton *rightButton;QPushButton *upButton;QPushButton *downButton;QPushButton *aButton;QPushButton *bButton;};#endif // HTetrisWINDOW_H/**Filename: HTetrisWindow.cpp*Author: Hale Chan <halechan@>*Date: 2011-11-24*/#include "HTetrisWindow.h"#include "HTetrisBoard.h"#include <QtGui>HTetrisWindow::HTetrisWindow(){board = new HTetrisBoard;nextPieceLabel = new QLabel;nextPieceLabel->setFrameStyle(QFrame::Box | QFrame::Raised);nextPieceLabel->setAlignment(Qt::AlignCenter);nextPieceLabel->setBaseSize(60, 60);nextPieceLabel->setMinimumSize(60, 60);nextPieceLabel->setMaximumSize(60,60);nextPieceLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); board->setNextPieceLabel(nextPieceLabel);scoreLcd = new QLCDNumber(6);scoreLcd->setSegmentStyle(QLCDNumber::Filled);scoreLcd->setFixedWidth(70);levelLcd = new QLCDNumber(1);levelLcd->setSegmentStyle(QLCDNumber::Filled);levelLcd->setFixedWidth(70);leftButton = new QPushButton;leftButton->setAutoRepeat(true);leftButton->setIcon(QIcon(":/images/left.png"));rightButton = new QPushButton;rightButton->setAutoRepeat(true);rightButton->setIcon(QIcon(":/images/right.png"));upButton = new QPushButton;upButton->setIcon(QIcon(":/images/up.png"));downButton = new QPushButton;downButton->setAutoRepeat(true);downButton->setIcon(QIcon(":/images/down.png"));aButton = new QPushButton(tr("A"));aButton->setFixedWidth(50);bButton = new QPushButton(tr("B"));bButton->setFixedWidth(50);connect(leftButton, SIGNAL(clicked()), board, SLOT(moveLeft()));connect(rightButton, SIGNAL(clicked()), board, SLOT(moveRight()));connect(upButton, SIGNAL(clicked()), board, SLOT(pause()));connect(downButton, SIGNAL(clicked()), board, SLOT(moveDown()));connect(aButton, SIGNAL(clicked()), board, SLOT(rotateLeft()));connect(bButton, SIGNAL(clicked()), board, SLOT(rotateRight()));connect(board, SIGNAL(levelChanged(int)), levelLcd, SLOT(display(int))); connect(board, SIGNAL(scoreChanged(int)), scoreLcd, SLOT(display(int)));QGridLayout *mainLayout = new QGridLayout;mainLayout->addWidget(board, 0, 0, 7, 3, Qt::AlignCenter);mainLayout->addWidget(createLabel(tr("Next")), 0, 3, Qt::AlignCenter);mainLayout->addWidget(nextPieceLabel, 1, 3, Qt::AlignCenter);mainLayout->setRowStretch(2, 9);mainLayout->addWidget(createLabel(tr("Score")), 3, 3, Qt::AlignCenter); mainLayout->addWidget(scoreLcd, 4, 3, Qt::AlignHCenter | Qt::AlignTop); mainLayout->addWidget(createLabel(tr("Level")), 5, 3, Qt::AlignCenter); mainLayout->addWidget(levelLcd, 6, 3, Qt::AlignHCenter | Qt::AlignTop); mainLayout->addWidget(upButton, 7, 1, Qt::AlignBottom);mainLayout->addWidget(aButton, 7, 3, Qt::AlignBottom | Qt::AlignHCenter); mainLayout->addWidget(leftButton, 8, 0, Qt::AlignTop | Qt::AlignLeft);mainLayout->addWidget(downButton, 8, 1, Qt::AlignBottom);mainLayout->addWidget(rightButton, 8, 2, Qt::AlignRight | Qt::AlignTop); mainLayout->addWidget(bButton, 8, 3, Qt::AlignBottom | Qt::AlignHCenter); mainLayout->setRowMinimumHeight(7, 30);mainLayout->setRowMinimumHeight(8, 50);this->setLayout(mainLayout);this->setWindowTitle(tr("Tetris"));this->setFixedSize(240, 400);}QLabel *HTetrisWindow::createLabel(const QString &text){QLabel *lbl = new QLabel(text);lbl->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);return lbl;}/**Filename: HTetrisPiece.h*Author: Hale Chan <halechan@>*Date: 2011-11-24*/#ifndef HTetrisPIECE_H#define HTetrisPIECE_Htypedef enum{HTetrisPieceShapeNone,HTetrisPieceShapeI,HTetrisPieceShapeT,HTetrisPieceShapeJ,HTetrisPieceShapeL,HTetrisPieceShapeO,HTetrisPieceShapeZ,HTetrisPieceShapeS}HTetrisPieceShape;typedef enum{HTetrisPieceRotateZero,HTetrisPieceRotate90,HTetrisPieceRotate180,HTetrisPieceRotate270}HTetrisPieceRotate;class HTetrisPiece{public:HTetrisPiece(){setShape(HTetrisPieceShapeNone);}void setRandomShape();void setShape(HTetrisPieceShape shape);HTetrisPieceShape shape() const { return pieceShape; } int x(int index) const { return coords[index][0]; }int y(int index) const { return coords[index][1]; }int minX() const;int maxX() const;int minY() const;int maxY() const;void setRotate(HTetrisPieceRotate rotate);HTetrisPiece pieceFromRotatedLeft() const;HTetrisPiece pieceFromRotatedRight() const;private:void setX(int index, int x) { coords[index][0] = x; } void setY(int index, int y) { coords[index][1] = y; }HTetrisPieceShape pieceShape;int coords[4][2];};#endif // HTetrisPIECE_H/**Filename: HTetrispiece.cpp*Author: Hale Chan <halechan@>*Date: 2011-11-24*/#include "HTetrisPiece.h"#include <QtCore>static const int coordsTable[8][4][2] = {{{0, 0}, {0, 0}, {0, 0}, {0, 0}},{{0, -1}, {0, 0}, {0, 1}, {0, 2}},{{-1, 0}, {0, 0}, {1, 0}, {0, 1}},{{0, -1}, {0, 0}, {0, 1}, {-1, 1}},{{0, -1}, {0, 0}, {0, 1}, {1, 1}},{{0, 0}, {1, 0}, {1, 1}, {0, 1}},{{-1, -1}, {0, -1}, {0, 0}, {1, 0}},{{1, -1}, {0, -1}, {0, 0}, {-1, 0}}};void HTetrisPiece::setRandomShape(){setShape((HTetrisPieceShape)(qrand() % 7 + 1));}void HTetrisPiece::setShape(HTetrisPieceShape shape) {for (int i=0; i<4; i++){coords[i][0] = coordsTable[shape][i][0];coords[i][1] = coordsTable[shape][i][1];}pieceShape = shape;}int HTetrisPiece::minX()const{int min = coords[0][0];for (int i = 1; i < 4; ++i)min = qMin(min, coords[i][0]);return min;}int HTetrisPiece::maxX()const{int max = coords[0][0];for (int i = 1; i < 4; ++i)max = qMax(max, coords[i][0]);return max;}int HTetrisPiece::minY()const{int min = coords[0][1];for (int i = 1; i < 4; ++i)min = qMin(min, coords[i][1]);return min;}int HTetrisPiece::maxY()const{int max = coords[0][1];for (int i = 1; i < 4; ++i)max = qMax(max, coords[i][1]);return max;}void HTetrisPiece::setRotate(HTetrisPieceRotate rotate) {switch(rotate){case HTetrisPieceRotate90:for(int i=0; i<4; i++){int tmp = x(i);setX(i,-y(i));setY(i, tmp);}break;case HTetrisPieceRotate180:for(int i=0; i<4; i++){setX(i,-x(i));setY(i, -y(i));}break;case HTetrisPieceRotate270:for(int i=0; i<4; i++){int tmp = x(i);setX(i,y(i));setY(i, -tmp);}break;default:break;}}HTetrisPiece HTetrisPiece::pieceFromRotatedLeft()const {if (pieceShape == HTetrisPieceShapeO)return *this;HTetrisPiece result;result.pieceShape = pieceShape;for (int i = 0; i < 4; ++i) {result.setX(i, y(i));result.setY(i, -x(i));}return result;}HTetrisPiece HTetrisPiece::pieceFromRotatedRight()const {if (pieceShape == HTetrisPieceShapeO)return *this;HTetrisPiece result;result.pieceShape = pieceShape;for (int i = 0; i < 4; ++i) {result.setX(i, -y(i));result.setY(i, x(i));}return result;}/**Filename: HTetrisBoard.h*Author: Hale Chan <halechan@>*Date: 2011-11-24*/#ifndef HTetrisBOARD_H#define HTetrisBOARD_H#include <QBasicTimer>#include <QFrame>#include <QPointer>#include "HTetrisPiece.h"class QLabel;#define HTetrisBoardWidth 10#define HTetrisBoardHeight 20class HTetrisBoard : public QFrame{Q_OBJECTpublic:HTetrisBoard(QWidget *parent = 0);void setNextPieceLabel(QLabel *label);QSize sizeHint() const;QSize minimumSizeHint() const;public slots:void start();void pause();void moveRight();void moveLeft();void moveDown();void rotateRight();void rotateLeft();signals:void scoreChanged(int score);void levelChanged(int level);protected:void paintEvent(QPaintEvent *event);void keyPressEvent(QKeyEvent *event);void timerEvent(QTimerEvent *event);private:HTetrisPieceShape &shapeAt(int x, int y) { return board[(y * HTetrisBoardWidth) + x]; } int timeoutTime() { return 1000 / level; }int squareWidth() { return contentsRect().width() / HTetrisBoardWidth; }int squareHeight() { return contentsRect().height() / HTetrisBoardHeight; }void clearBoard();void dropDown();void oneLineDown();void pieceDropped(int dropHeight);void removeFullLines();void newPiece();void showNextPiece();bool tryMove(const HTetrisPiece &newPiece, int newX, int newY);void drawSquare(QPainter &painter, int x, int y, HTetrisPieceShape shape);QBasicTimer timer;QPointer<QLabel> nextPieceLabel;bool isStarted;bool isPaused;bool isWaitingAfterLine;bool gameOver;HTetrisPiece curPiece;HTetrisPiece nextPiece;int curX;int curY;int score;int level;int exp;HTetrisPieceShape board[HTetrisBoardWidth * HTetrisBoardHeight]; };#endif // HTetrisBOARD_H/**Filename: HTetrisBoard.cpp*Author: Hale Chan <halechan@>*Date: 2011-11-24*/#include <QtGui>#include "HTetrisBoard.h"static const QRgb colorTable[8] = {0x000000,0x00F0F0,0xA000F0,0x0000F0,0xF0A000,0xF0F000,0xF00000,0x00F000};HTetrisBoard::HTetrisBoard(QWidget *parent): QFrame(parent){setFrameStyle(QFrame::Panel | QFrame::Sunken);setFocusPolicy(Qt::StrongFocus);isStarted = false;isPaused = false;gameOver = false;clearBoard();nextPiece.setRandomShape();nextPiece.setRotate((HTetrisPieceRotate)(qrand()%4));}void HTetrisBoard::setNextPieceLabel(QLabel *label){nextPieceLabel = label;}QSize HTetrisBoard::sizeHint() const{return QSize(HTetrisBoardWidth * 15 + frameWidth() * 2,HTetrisBoardHeight * 15 + frameWidth() * 2);}QSize HTetrisBoard::minimumSizeHint() const{return QSize(HTetrisBoardWidth * 5 + frameWidth() * 2,HTetrisBoardHeight * 5 + frameWidth() * 2);}void HTetrisBoard::start(){if (isPaused)return;isStarted = true;gameOver = false;isWaitingAfterLine = false;score = 0;level = 1;clearBoard();emit scoreChanged(score);emit levelChanged(level);newPiece();timer.start(timeoutTime(), this);}void HTetrisBoard::pause(){if (!isStarted){start();return;}isPaused = !isPaused;if (isPaused) {timer.stop();} else {timer.start(timeoutTime(), this);}update();}void HTetrisBoard::paintEvent(QPaintEvent *event){QFrame::paintEvent(event);QPainter painter(this);QRect rect = contentsRect();int boardTop = rect.bottom() - HTetrisBoardHeight*squareHeight();for (int i = 0; i < HTetrisBoardHeight; ++i) {for (int j = 0; j < HTetrisBoardWidth; ++j) {HTetrisPieceShape shape = shapeAt(j, HTetrisBoardHeight - i - 1); if (shape != HTetrisPieceShapeNone)drawSquare(painter, rect.left() + j * squareWidth(),boardTop + i * squareHeight(), shape);}}if (curPiece.shape() != HTetrisPieceShapeNone) {for (int i = 0; i < 4; ++i) {int x = curX + curPiece.x(i);int y = curY - curPiece.y(i);drawSquare(painter, rect.left() + x * squareWidth(),boardTop + (HTetrisBoardHeight - y - 1) * squareHeight(), curPiece.shape());}}painter.setPen(QColor(255, 0, 0));if (isPaused) {painter.drawText(rect, Qt::AlignCenter, tr("Paused"));}if (gameOver){painter.drawText(rect, Qt::AlignCenter, tr("Game Over"));}}void HTetrisBoard::keyPressEvent(QKeyEvent *event){if (!isStarted || isPaused || curPiece.shape() == HTetrisPieceShapeNone) { if(isPaused && event->key() == Qt::Key_Up){pause();}QFrame::keyPressEvent(event);return;}switch (event->key()) {case Qt::Key_Left:tryMove(curPiece, curX - 1, curY);break;case Qt::Key_Right:tryMove(curPiece, curX + 1, curY);break;case Qt::Key_Down:oneLineDown();break;case Qt::Key_Up:pause();break;case Qt::Key_A:tryMove(curPiece.pieceFromRotatedLeft(), curX, curY);break;case Qt::Key_B:tryMove(curPiece.pieceFromRotatedRight(), curX, curY);break;default:QFrame::keyPressEvent(event);}}void HTetrisBoard::timerEvent(QTimerEvent *event){if (event->timerId() == timer.timerId()) {if (isWaitingAfterLine) {isWaitingAfterLine = false;newPiece();timer.start(timeoutTime(), this);} else {oneLineDown();}} else {QFrame::timerEvent(event);}}void HTetrisBoard::clearBoard(){for (int i = 0; i < HTetrisBoardHeight * HTetrisBoardWidth; ++i) board[i] = HTetrisPieceShapeNone;}void HTetrisBoard::dropDown(){int dropHeight = 0;int newY = curY;while (newY > 0) {if (!tryMove(curPiece, curX, newY - 1))break;--newY;++dropHeight;}pieceDropped(dropHeight);}void HTetrisBoard::oneLineDown(){if (!tryMove(curPiece, curX, curY - 1))pieceDropped(0);}void HTetrisBoard::pieceDropped(int dropHeight){for (int i = 0; i < 4; ++i) {int x = curX + curPiece.x(i);int y = curY - curPiece.y(i);shapeAt(x, y) = curPiece.shape();}exp += 1;score += dropHeight+1;emit scoreChanged(score);removeFullLines();if(exp%50 == 0){level++;timer.start(timeoutTime(), this);emit levelChanged(level);}if (!isWaitingAfterLine)newPiece();}void HTetrisBoard::removeFullLines(){int numFullLines = 0;for (int i = HTetrisBoardHeight - 1; i >= 0; --i) {bool lineIsFull = true;for (int j = 0; j < HTetrisBoardWidth; ++j) {if (shapeAt(j, i) == HTetrisPieceShapeNone) {lineIsFull = false;break;}}if (lineIsFull) {++numFullLines;for (int k = i; k < HTetrisBoardHeight - 1; ++k) {for (int j = 0; j < HTetrisBoardWidth; ++j)shapeAt(j, k) = shapeAt(j, k + 1);}for (int j = 0; j < HTetrisBoardWidth; ++j)shapeAt(j, HTetrisBoardHeight - 1) = HTetrisPieceShapeNone; }}if (numFullLines > 0) {switch(numFullLines){case 1:exp += 1;score += 10;break;case 2:exp += 2;score += 20;break;case 3:exp += 3;score += 30;break;case 4:exp += 5;score += 50;break;}emit scoreChanged(score);timer.start(500, this);isWaitingAfterLine = true;curPiece.setShape(HTetrisPieceShapeNone);update();}}void HTetrisBoard::newPiece(){curPiece = nextPiece;nextPiece.setRandomShape();nextPiece.setRotate((HTetrisPieceRotate)(qrand()%4));showNextPiece();curX = HTetrisBoardWidth / 2;curY = HTetrisBoardHeight - 1 + curPiece.minY();if (!tryMove(curPiece, curX, curY)) {curPiece.setShape(HTetrisPieceShapeNone);timer.stop();isStarted = false;gameOver = true;update();}}void HTetrisBoard::showNextPiece(){if (!nextPieceLabel)return;int dx = nextPiece.maxX() - nextPiece.minX() + 1;int dy = nextPiece.maxY() - nextPiece.minY() + 1;QPixmap pixmap(dx * squareWidth(), dy * squareHeight());QPainter painter(&pixmap);painter.fillRect(pixmap.rect(), nextPieceLabel->palette().background());for (int i = 0; i < 4; ++i) {int x = nextPiece.x(i) - nextPiece.minX();int y = nextPiece.y(i) - nextPiece.minY();drawSquare(painter, x * squareWidth(), y * squareHeight(),nextPiece.shape());}nextPieceLabel->setPixmap(pixmap);}bool HTetrisBoard::tryMove(const HTetrisPiece &newPiece, int newX, int newY){for (int i = 0; i < 4; ++i) {int x = newX + newPiece.x(i);int y = newY - newPiece.y(i);if (x < 0 || x >= HTetrisBoardWidth || y < 0 || y >= HTetrisBoardHeight)return false;if (shapeAt(x, y) != HTetrisPieceShapeNone)return false;}curPiece = newPiece;curX = newX;curY = newY;update();return true;}void HTetrisBoard::drawSquare(QPainter &painter, int x, int y, HTetrisPieceShape shape) {QColor color = colorTable[(int)(shape)];painter.fillRect(x + 1, y + 1, squareWidth() - 2, squareHeight() - 2, color);painter.setPen(color.light());painter.drawLine(x, y + squareHeight() - 1, x, y);painter.drawLine(x, y, x + squareWidth() - 1, y);painter.setPen(color.dark());painter.drawLine(x + 1, y + squareHeight() - 1,x + squareWidth() - 1, y + squareHeight() - 1);painter.drawLine(x + squareWidth() - 1, y + squareHeight() - 1,x + squareWidth() - 1, y + 1);}void HTetrisBoard::moveLeft(){tryMove(curPiece, curX - 1, curY);}void HTetrisBoard::moveRight(){tryMove(curPiece, curX + 1, curY);}void HTetrisBoard::moveDown(){oneLineDown();}void HTetrisBoard::rotateLeft(){tryMove(curPiece.pieceFromRotatedLeft(), curX, curY);}void HTetrisBoard::rotateRight(){tryMove(curPiece.pieceFromRotatedRight(), curX, curY);}。

相关主题