diff --git a/Tetris_task.pro b/Tetris_task.pro new file mode 100644 index 0000000..ade1f6b --- /dev/null +++ b/Tetris_task.pro @@ -0,0 +1,30 @@ +QT += core gui +QT += multimedia +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# You can make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + tetrixboard.cpp \ + tetrixpiece.cpp \ + tetrixwindow.cpp + +HEADERS += \ + tetrixboard.h \ + tetrixpiece.h \ + tetrixwindow.h + +FORMS += + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +DISTFILES += \ + Video_Game_Players_-_Tetris_Theme_48152782.mp3 diff --git a/Tetris_task.pro.user b/Tetris_task.pro.user new file mode 100644 index 0000000..6356787 --- /dev/null +++ b/Tetris_task.pro.user @@ -0,0 +1,425 @@ + + + + + + EnvironmentId + {4f500388-fdcc-4898-ad1a-0bc7990e4420} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + false + true + false + 0 + true + true + 0 + 8 + true + false + 1 + true + true + true + *.md, *.MD, Makefile + false + true + + + + ProjectExplorer.Project.PluginSettings + + + true + false + true + true + true + true + + + 0 + true + + -fno-delayed-template-parsing + + true + Builtin.BuildSystem + + true + true + Builtin.DefaultTidyAndClazy + 6 + + + + true + + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop Qt 5.12.12 MinGW 64-bit + Desktop Qt 5.12.12 MinGW 64-bit + qt.qt5.51212.win64_mingw73_kit + 0 + 0 + 0 + + 0 + C:\Users\mefby\OneDrive\Документы\7_семестр\Плюсы и QT\build-Tetris_task-Desktop_Qt_5_12_12_MinGW_64_bit-Debug + C:/Users/mefby/OneDrive/Документы/7_семестр/Плюсы и QT/build-Tetris_task-Desktop_Qt_5_12_12_MinGW_64_bit-Debug + + + true + QtProjectManager.QMakeBuildStep + false + + + + true + Qt4ProjectManager.MakeStep + + 2 + Сборка + Сборка + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + clean + + 1 + Очистка + Очистка + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Отладка + Qt4ProjectManager.Qt4BuildConfiguration + 2 + + + C:\Users\mefby\OneDrive\Документы\7_семестр\Плюсы и QT\build-Tetris_task-Desktop_Qt_5_12_12_MinGW_64_bit-Release + C:/Users/mefby/OneDrive/Документы/7_семестр/Плюсы и QT/build-Tetris_task-Desktop_Qt_5_12_12_MinGW_64_bit-Release + + + true + QtProjectManager.QMakeBuildStep + false + + + + true + Qt4ProjectManager.MakeStep + + 2 + Сборка + Сборка + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + clean + + 1 + Очистка + Очистка + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Выпуск + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 0 + + + 0 + C:\Users\mefby\OneDrive\Документы\7_семестр\Плюсы и QT\build-Tetris_task-Desktop_Qt_5_12_12_MinGW_64_bit-Profile + C:/Users/mefby/OneDrive/Документы/7_семестр/Плюсы и QT/build-Tetris_task-Desktop_Qt_5_12_12_MinGW_64_bit-Profile + + + true + QtProjectManager.QMakeBuildStep + false + + + + true + Qt4ProjectManager.MakeStep + + 2 + Сборка + Сборка + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + clean + + 1 + Очистка + Очистка + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Профилирование + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 0 + 0 + + 3 + + + 0 + Развёртывание + Развёртывание + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + ProjectExplorer.DefaultDeployConfiguration + + 1 + + true + true + true + + 2 + + Qt4ProjectManager.Qt4RunConfiguration:C:/qt_projects/Tetris_task/Tetris_task.pro + C:/qt_projects/Tetris_task/Tetris_task.pro + false + true + true + false + true + C:/Users/mefby/OneDrive/Документы/7_семестр/Плюсы и QT/build-Tetris_task-Desktop_Qt_5_12_12_MinGW_64_bit-Debug + + 1 + + + + ProjectExplorer.Project.Target.1 + + Desktop + Desktop Qt 5.12.12 MinGW 32-bit + Desktop Qt 5.12.12 MinGW 32-bit + qt.qt5.51212.win32_mingw73_kit + 0 + 0 + 0 + + 0 + C:\Users\mefby\OneDrive\Документы\7_семестр\Плюсы и QT\build-Tetris_task-Desktop_Qt_5_12_12_MinGW_32_bit-Debug + C:/Users/mefby/OneDrive/Документы/7_семестр/Плюсы и QT/build-Tetris_task-Desktop_Qt_5_12_12_MinGW_32_bit-Debug + + + true + QtProjectManager.QMakeBuildStep + false + + + + true + Qt4ProjectManager.MakeStep + + 2 + Сборка + Сборка + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + clean + + 1 + Очистка + Очистка + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Отладка + Qt4ProjectManager.Qt4BuildConfiguration + 2 + + + C:\Users\mefby\OneDrive\Документы\7_семестр\Плюсы и QT\build-Tetris_task-Desktop_Qt_5_12_12_MinGW_32_bit-Release + C:/Users/mefby/OneDrive/Документы/7_семестр/Плюсы и QT/build-Tetris_task-Desktop_Qt_5_12_12_MinGW_32_bit-Release + + + true + QtProjectManager.QMakeBuildStep + false + + + + true + Qt4ProjectManager.MakeStep + + 2 + Сборка + Сборка + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + clean + + 1 + Очистка + Очистка + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Выпуск + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 0 + + + 0 + C:\Users\mefby\OneDrive\Документы\7_семестр\Плюсы и QT\build-Tetris_task-Desktop_Qt_5_12_12_MinGW_32_bit-Profile + C:/Users/mefby/OneDrive/Документы/7_семестр/Плюсы и QT/build-Tetris_task-Desktop_Qt_5_12_12_MinGW_32_bit-Profile + + + true + QtProjectManager.QMakeBuildStep + false + + + + true + Qt4ProjectManager.MakeStep + + 2 + Сборка + Сборка + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + clean + + 1 + Очистка + Очистка + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Профилирование + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 0 + 0 + + 3 + + + 0 + Развёртывание + Развёртывание + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + ProjectExplorer.DefaultDeployConfiguration + + 1 + + true + true + true + + 2 + + Qt4ProjectManager.Qt4RunConfiguration:C:/qt_projects/Tetris_task/Tetris_task.pro + C:/qt_projects/Tetris_task/Tetris_task.pro + false + true + true + false + true + + 1 + + + + ProjectExplorer.Project.TargetCount + 2 + + + ProjectExplorer.Project.Updater.FileVersion + 22 + + + Version + 22 + + diff --git a/Video_Game_Players_-_Tetris_Theme_48152782.mp3 b/Video_Game_Players_-_Tetris_Theme_48152782.mp3 new file mode 100644 index 0000000..225519d Binary files /dev/null and b/Video_Game_Players_-_Tetris_Theme_48152782.mp3 differ diff --git a/main.cpp b/main.cpp index f1c8bd9..838d55b 100644 --- a/main.cpp +++ b/main.cpp @@ -1,10 +1,22 @@ -#include - -#include "tetris.h" - -int main(int argc, char *argv[]) { - QApplication a(argc, argv); - Tetris w; - w.show(); - return a.exec(); -} +#include "tetrixwindow.h" + +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + TetrixWindow window; + window.show(); + QMediaPlaylist *playlist = new QMediaPlaylist(); + playlist->addMedia(QUrl("qrc:/tetris_music/background.wav")); + playlist->setPlaybackMode(QMediaPlaylist::Loop); + QMediaPlayer *player = new QMediaPlayer; + player->setMedia(playlist); + player->setVolume(10); + player->play(); + return app.exec(); +} diff --git a/tetrisform.cpp b/tetrisform.cpp new file mode 100644 index 0000000..9156998 --- /dev/null +++ b/tetrisform.cpp @@ -0,0 +1,14 @@ +#include "tetrisform.h" +#include "ui_tetrisform.h" + +tetrisForm::tetrisForm(QWidget *parent) : + QWidget(parent), + ui(new Ui::tetrisForm) +{ + ui->setupUi(this); +} + +tetrisForm::~tetrisForm() +{ + delete ui; +} diff --git a/tetrismainwindow.cpp b/tetrismainwindow.cpp new file mode 100644 index 0000000..9e4f7d9 --- /dev/null +++ b/tetrismainwindow.cpp @@ -0,0 +1,15 @@ +#include "tetrismainwindow.h" +#include "ui_tetrismainwindow.h" + +TetrisMainWindow::TetrisMainWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::TetrisMainWindow) +{ + ui->setupUi(this); +} + +TetrisMainWindow::~TetrisMainWindow() +{ + delete ui; +} + diff --git a/tetrismainwindow.h b/tetrismainwindow.h new file mode 100644 index 0000000..84c4696 --- /dev/null +++ b/tetrismainwindow.h @@ -0,0 +1,31 @@ +#ifndef TETRISMAINWINDOW_H +#define TETRISMAINWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class TetrisMainWindow; } +QT_END_NAMESPACE + +class TetrisMainWindow : public QWidget +{ + Q_OBJECT + +public: + TetrisMainWindow(QWidget *parent = nullptr); + ~TetrisMainWindow(); + +private: + Ui::TetrisMainWindow *ui; + QLabel *createLabel(const QString &text); + + TetrisBoard *board; + QLabel *nextPieceLabel; + QLCDNumber *scoreLcd; + QLCDNumber *levelLcd; + QLCDNumber *linesLcd; + QPushButton *startButton; + QPushButton *quitButton; + QPushButton *pauseButton; +}; +#endif // TETRISMAINWINDOW_H diff --git a/tetrismainwindow.ui b/tetrismainwindow.ui new file mode 100644 index 0000000..8127c88 --- /dev/null +++ b/tetrismainwindow.ui @@ -0,0 +1,19 @@ + + + TetrisMainWindow + + + + 0 + 0 + 800 + 600 + + + + TetrisMainWindow + + + + + diff --git a/tetrixboard.cpp b/tetrixboard.cpp new file mode 100644 index 0000000..1ef4abf --- /dev/null +++ b/tetrixboard.cpp @@ -0,0 +1,283 @@ +#include "tetrixboard.h" + +#include +#include +#include +#include + +TetrixBoard::TetrixBoard(QWidget *parent) + : QFrame(parent), isStarted(false) +{ + setFrameStyle(QFrame::Panel | QFrame::Sunken); + setFocusPolicy(Qt::StrongFocus); + clearBoard(); + + nextPiece.setRandomShape(); +} + +void TetrixBoard::setNextPieceLabel(QLabel *label) +{ + nextPieceLabel = label; +} + +QSize TetrixBoard::sizeHint() const +{ + return QSize(BoardWidth * 15 + frameWidth() * 2, + BoardHeight * 15 + frameWidth() * 2); +} + +QSize TetrixBoard::minimumSizeHint() const + +{ + return QSize(BoardWidth * 5 + frameWidth() * 2, + BoardHeight * 5 + frameWidth() * 2); +} + +void TetrixBoard::start() +{ + + isStarted = true; + isWaitingAfterLine = false; + numLinesRemoved = 0; + numPiecesDropped = 0; + score = 0; + clearBoard(); + + emit linesRemovedChanged(numLinesRemoved); + emit scoreChanged(score); + + newPiece(); + timer.start(timeoutTime(), this); +} + +void TetrixBoard::paintEvent(QPaintEvent *event) +{ + QFrame::paintEvent(event); + + QPainter painter(this); + QRect rect = contentsRect(); + + int boardTop = rect.bottom() - BoardHeight*squareHeight(); + + for (int i = 0; i < BoardHeight; ++i) { + for (int j = 0; j < BoardWidth; ++j) { + TetrixShape shape = shapeAt(j, BoardHeight - i - 1); + if (shape != NoShape) + drawSquare(painter, rect.left() + j * squareWidth(), + boardTop + i * squareHeight(), shape); + } + } + if (curPiece.shape() != NoShape) { + 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 + (BoardHeight - y - 1) * squareHeight(), + curPiece.shape()); + } + } +} + +void TetrixBoard::keyPressEvent(QKeyEvent *event) +{ + if (!isStarted || curPiece.shape() == NoShape) { + 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_Up: + tryMove(curPiece.rotatedLeft(), curX, curY); + break; + case Qt::Key_Space: + dropDown(); + break; + case Qt::Key_Down: + oneLineDown(); + break; + default: + QFrame::keyPressEvent(event); + } +} + +void TetrixBoard::timerEvent(QTimerEvent *event) +{ + if (event->timerId() == timer.timerId()) { + if (isWaitingAfterLine) { + isWaitingAfterLine = false; + newPiece(); + timer.start(timeoutTime(), this); + } else { + oneLineDown(); + } + } else { + QFrame::timerEvent(event); + } +} + +void TetrixBoard::clearBoard() +{ + for (int i = 0; i < BoardHeight * BoardWidth; ++i) + board[i] = NoShape; +} + +void TetrixBoard::dropDown() +{ + int dropHeight = 0; + int newY = curY; + while (newY > 0) { + if (!tryMove(curPiece, curX, newY - 1)) + break; + --newY; + ++dropHeight; + } + pieceDropped(dropHeight); +} + +void TetrixBoard::oneLineDown() +{ + if (!tryMove(curPiece, curX, curY - 1)) + pieceDropped(0); +} + +void TetrixBoard::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(); + } + + ++numPiecesDropped; + + score += dropHeight + 7; + emit scoreChanged(score); + removeFullLines(); + + if (!isWaitingAfterLine) + newPiece(); +} + +void TetrixBoard::removeFullLines() +{ + int numFullLines = 0; + + for (int i = BoardHeight - 1; i >= 0; --i) { + bool lineIsFull = true; + + for (int j = 0; j < BoardWidth; ++j) { + if (shapeAt(j, i) == NoShape) { + lineIsFull = false; + break; + } + } + + if (lineIsFull) { + + ++numFullLines; + for (int k = i; k < BoardHeight - 1; ++k) { + for (int j = 0; j < BoardWidth; ++j) + shapeAt(j, k) = shapeAt(j, k + 1); + } + + for (int j = 0; j < BoardWidth; ++j) + shapeAt(j, BoardHeight - 1) = NoShape; + } + } + + + + if (numFullLines > 0) { + numLinesRemoved += numFullLines; + score += 10 * numFullLines; + emit linesRemovedChanged(numLinesRemoved); + emit scoreChanged(score); + + timer.start(500, this); + isWaitingAfterLine = true; + curPiece.setShape(NoShape); + update(); + } +} + +void TetrixBoard::newPiece() +{ + curPiece = nextPiece; + nextPiece.setRandomShape(); + showNextPiece(); + curX = BoardWidth / 2 + 1; + curY = BoardHeight - 1 + curPiece.minY(); + + if (!tryMove(curPiece, curX, curY)) { + curPiece.setShape(NoShape); + timer.stop(); + isStarted = false; + } +} + +void TetrixBoard::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().window()); + + 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 TetrixBoard::tryMove(const TetrixPiece &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 >= BoardWidth || y < 0 || y >= BoardHeight) + return false; + if (shapeAt(x, y) != NoShape) + return false; + } + + curPiece = newPiece; + curX = newX; + curY = newY; + update(); + return true; +} + +void TetrixBoard::drawSquare(QPainter &painter, int x, int y, TetrixShape shape) +{ + static constexpr QRgb colorTable[8] = { + 0xFF3300, 0xCC6666, 0x66CC66, 0x6666CC, + 0xCCCC66, 0x33FFFF, 0x66CCCC, 0xFF9900 + }; + + QColor color = colorTable[int(shape)]; + painter.fillRect(x + 1, y + 1, squareWidth() - 2, squareHeight() - 2, + color); + + painter.setPen(color.lighter()); + painter.drawLine(x, y + squareHeight() - 1, x, y); + painter.drawLine(x, y, x + squareWidth() - 1, y); + + painter.setPen(color.darker()); + 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); +} diff --git a/tetrixboard.h b/tetrixboard.h new file mode 100644 index 0000000..b237c91 --- /dev/null +++ b/tetrixboard.h @@ -0,0 +1,69 @@ +#ifndef TETRIXBOARD_H +#define TETRIXBOARD_H + +#include +#include +#include + +#include "tetrixpiece.h" + +QT_BEGIN_NAMESPACE +class QLabel; +QT_END_NAMESPACE + +class TetrixBoard : public QFrame +{ + Q_OBJECT + +public: + TetrixBoard(QWidget *parent = nullptr); + + void setNextPieceLabel(QLabel *label); + QSize sizeHint() const override; + QSize minimumSizeHint() const override; + +public slots: + void start(); + void pause(); + +signals: + void scoreChanged(int score); + void linesRemovedChanged(int numLines); + +protected: + void paintEvent(QPaintEvent *event) override; + void keyPressEvent(QKeyEvent *event) override; + void timerEvent(QTimerEvent *event) override; + +private: + enum { BoardWidth = 12, BoardHeight = 24 }; + + TetrixShape &shapeAt(int x, int y) { return board[(y * BoardWidth) + x]; } + int timeoutTime() { return 1000; } + int squareWidth() { return contentsRect().width() / BoardWidth; } + int squareHeight() { return contentsRect().height() / BoardHeight; } + void clearBoard(); + void dropDown(); + void oneLineDown(); + void pieceDropped(int dropHeight); + void removeFullLines(); + void newPiece(); + void showNextPiece(); + bool tryMove(const TetrixPiece &newPiece, int newX, int newY); + void drawSquare(QPainter &painter, int x, int y, TetrixShape shape); + + QBasicTimer timer; + QPointer nextPieceLabel; + bool isStarted; + bool isWaitingAfterLine; + TetrixPiece curPiece; + TetrixPiece nextPiece; + int curX; + int curY; + int numLinesRemoved; + int numPiecesDropped; + int score; + TetrixShape board[BoardWidth * BoardHeight]; +}; + +#endif diff --git a/tetrixpiece.cpp b/tetrixpiece.cpp new file mode 100644 index 0000000..eab5cf7 --- /dev/null +++ b/tetrixpiece.cpp @@ -0,0 +1,77 @@ +#include "tetrixpiece.h" + +#include + +void TetrixPiece::setRandomShape() +{ + setShape(TetrixShape(QRandomGenerator::global()->bounded(7) + 1)); +} + +void TetrixPiece::setShape(TetrixShape shape) +{ + static constexpr int coordsTable[8][4][2] = { + { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, + { { 0, -1 }, { 0, 0 }, { -1, 0 }, { -1, 1 } }, + { { 0, -1 }, { 0, 0 }, { 1, 0 }, { 1, 1 } }, + { { 0, -1 }, { 0, 0 }, { 0, 1 }, { 0, 2 } }, + { { -1, 0 }, { 0, 0 }, { 1, 0 }, { 0, 1 } }, + { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } }, + { { -1, -1 }, { 0, -1 }, { 0, 0 }, { 0, 1 } }, + { { 1, -1 }, { 0, -1 }, { 0, 0 }, { 0, 1 } } + }; + + for (int i = 0; i < 4 ; i++) { + for (int j = 0; j < 2; ++j) + coords[i][j] = coordsTable[shape][i][j]; + } + pieceShape = shape; +} + +int TetrixPiece::minX() const +{ + int min = coords[0][0]; + for (int i = 1; i < 4; ++i) + min = qMin(min, coords[i][0]); + return min; +} + +int TetrixPiece::maxX() const + +{ + int max = coords[0][0]; + for (int i = 1; i < 4; ++i) + max = qMax(max, coords[i][0]); + return max; +} + +int TetrixPiece::minY() const +{ + int min = coords[0][1]; + for (int i = 1; i < 4; ++i) + min = qMin(min, coords[i][1]); + return min; +} + +int TetrixPiece::maxY() const + +{ + int max = coords[0][1]; + for (int i = 1; i < 4; ++i) + max = qMax(max, coords[i][1]); + return max; +} + +TetrixPiece TetrixPiece::rotatedLeft() const +{ + if (pieceShape == SquareShape) + return *this; + + TetrixPiece result; + result.pieceShape = pieceShape; + for (int i = 0; i < 4; ++i) { + result.setX(i, y(i)); + result.setY(i, -x(i)); + } + return result; +} + diff --git a/tetrixpiece.h b/tetrixpiece.h new file mode 100644 index 0000000..89fe166 --- /dev/null +++ b/tetrixpiece.h @@ -0,0 +1,33 @@ +#ifndef TETRIXPIECE_H +#define TETRIXPIECE_H + +enum TetrixShape { NoShape, ZShape, SShape, LineShape, TShape, SquareShape, + LShape, MirroredLShape }; + +class TetrixPiece +{ +public: + TetrixPiece() { setShape(NoShape); } + + void setRandomShape(); + void setShape(TetrixShape shape); + + TetrixShape 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; + TetrixPiece rotatedLeft() const; + TetrixPiece rotatedRight() const; + +private: + void setX(int index, int x) { coords[index][0] = x; } + void setY(int index, int y) { coords[index][1] = y; } + + TetrixShape pieceShape; + int coords[4][2]; +}; + +#endif diff --git a/tetrixwindow.cpp b/tetrixwindow.cpp new file mode 100644 index 0000000..721970e --- /dev/null +++ b/tetrixwindow.cpp @@ -0,0 +1,61 @@ +#include "tetrixboard.h" +#include "tetrixwindow.h" + +#include +#include +#include +#include +#include + + +TetrixWindow::TetrixWindow(QWidget *parent) + : QWidget(parent), board(new TetrixBoard) +{ + + nextPieceLabel = new QLabel; + nextPieceLabel->setFrameStyle(QFrame::Box | QFrame::Raised); + nextPieceLabel->setAlignment(Qt::AlignCenter); + board->setNextPieceLabel(nextPieceLabel); + + scoreLcd = new QLCDNumber(5); + scoreLcd->setSegmentStyle(QLCDNumber::Filled); + + linesLcd = new QLCDNumber(5); + linesLcd->setSegmentStyle(QLCDNumber::Filled); + + startButton = new QPushButton(tr("&Новая игра")); + startButton->setFocusPolicy(Qt::NoFocus); + quitButton = new QPushButton(tr("&Выход")); + quitButton->setFocusPolicy(Qt::NoFocus); + + connect(startButton, &QPushButton::clicked, board, &TetrixBoard::start); + connect(quitButton , &QPushButton::clicked, qApp, &QCoreApplication::quit); + connect(board, &TetrixBoard::scoreChanged, + scoreLcd, QOverload::of(&QLCDNumber::display)); + connect(board, &TetrixBoard::linesRemovedChanged, + linesLcd, QOverload::of(&QLCDNumber::display)); + + QGridLayout *layout = new QGridLayout; + layout->addWidget(createLabel(tr("Следующая фигура")), 0, 0); + layout->addWidget(nextPieceLabel, 1, 0); + layout->addWidget(startButton, 4, 0); + layout->addWidget(board, 0, 1, 6, 1); + layout->addWidget(createLabel(tr("Счёт")), 0, 2); + layout->addWidget(scoreLcd, 1, 2); + layout->addWidget(createLabel(tr("Линий собрано")), 2, 2); + layout->addWidget(linesLcd, 3, 2); + layout->addWidget(quitButton, 4, 2); + setLayout(layout); + + setWindowTitle(tr("Тетрис")); + resize(550, 370); +} + +QLabel *TetrixWindow::createLabel(const QString &text) +{ + QLabel *label = new QLabel(text); + label->setAlignment(Qt::AlignHCenter | Qt::AlignBottom); + return label; +} + + diff --git a/tetrixwindow.h b/tetrixwindow.h new file mode 100644 index 0000000..53f367d --- /dev/null +++ b/tetrixwindow.h @@ -0,0 +1,31 @@ +#ifndef TETRIXWINDOW_H +#define TETRIXWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +class QLCDNumber; +class QLabel; +class QPushButton; +QT_END_NAMESPACE +class TetrixBoard; + +class TetrixWindow : public QWidget +{ + Q_OBJECT + +public: + TetrixWindow(QWidget *parent = nullptr); + +private: + QLabel *createLabel(const QString &text); + + TetrixBoard *board; + QLabel *nextPieceLabel; + QLCDNumber *scoreLcd; + QLCDNumber *linesLcd; + QPushButton *startButton; + QPushButton *quitButton; +}; + +#endif