From c2091f11034c144f00d81423a1b804eb81420126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B0=D0=B4=D0=B8=D0=BC?= <20000805@edu.spbgasu.ru> Date: Tue, 28 Nov 2023 23:30:20 +0300 Subject: [PATCH 1/3] Tetris Okhrimenko v1.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Из проблем на данный момент: 1) Нужно показывать следующую фигуру 2) Исправить код стайл 3) Проверить код на наличие лишнего "мусора" 4) Корректно обрабатывать проигрыш(сейчас немного не в тот момент срабатывает сигнал) --- TetrisTask.pro | 6 + gamefield.cpp | 361 +++++++++++++++++++++++++++++++++++++++++++-- gamefield.h | 85 +++++++++-- gameoverdialog.cpp | 14 ++ gameoverdialog.h | 22 +++ modaldialog.cpp | 14 ++ modaldialog.h | 22 +++ tetramino.cpp | 5 + tetramino.h | 14 ++ tetris.cpp | 146 +++++++++++++++++- tetris.h | 22 +++ 11 files changed, 686 insertions(+), 25 deletions(-) create mode 100644 gameoverdialog.cpp create mode 100644 gameoverdialog.h create mode 100644 modaldialog.cpp create mode 100644 modaldialog.h create mode 100644 tetramino.cpp create mode 100644 tetramino.h diff --git a/TetrisTask.pro b/TetrisTask.pro index f4de819..6629c01 100644 --- a/TetrisTask.pro +++ b/TetrisTask.pro @@ -10,11 +10,17 @@ CONFIG += c++17 SOURCES += \ gamefield.cpp \ + gameoverdialog.cpp \ main.cpp \ + modaldialog.cpp \ + tetramino.cpp \ tetris.cpp HEADERS += \ gamefield.h \ + gameoverdialog.h \ + modaldialog.h \ + tetramino.h \ tetris.h FORMS += \ diff --git a/gamefield.cpp b/gamefield.cpp index 6a5ce13..b97dc83 100644 --- a/gamefield.cpp +++ b/gamefield.cpp @@ -1,10 +1,13 @@ #include "gamefield.h" #include +#include +#include +#include +#include GameField::GameField(QWidget *parent) : QWidget{parent} { - connect(this, &GameField::InitialisationStarted, this, &GameField::SetCells, - Qt::QueuedConnection); + setStyleSheet("border: 4px solid black;"); emit InitialisationStarted(); } @@ -12,21 +15,359 @@ GameField::GameField(QWidget *parent) : QWidget{parent} { uint GameField::GetRowsNumber() const { return rowsNumber_; } void GameField::SetRowsNumber(uint rowsNumber) { - if (rowsNumber_ == rowsNumber) return; + if (rowsNumber_ == rowsNumber) return; - rowsNumber_ = rowsNumber; - emit RowsNumberChanged(); + rowsNumber_ = rowsNumber; + emit RowsNumberChanged(); + update(); } uint GameField::GetColumnsNumber() const { return columnsNumber_; } void GameField::SetColumnNumber(uint columnsCount) { - if (columnsNumber_ == columnsCount) return; + if (columnsNumber_ == columnsCount) return; - columnsNumber_ = columnsCount; - emit ColumnsNumberChanged(); + columnsNumber_ = columnsCount; + emit ColumnsNumberChanged(); + update(); } -void GameField::SetCells() { - qDebug() << rowsNumber_ << " " << columnsNumber_ << "|"; +void GameField::SetFigurePosition(int row, int column) { + if (column >= 0 && column + currentFigure_[0].size() <= columnsNumber_ && GameGrid_[row][column] != 1) { + currentFigureRow_ = row; + currentFigureColumn_ = column; + } + update(); } + +void GameField::spawnNextFigure() { + + int randNumb = 1 + rand() % 7; + //int randNumb = 4; + + switch (randNumb) { + case 1: + currentFigure_ = { + {1}, + {1}, + {1}, + {1} + }; + colorFigure = Qt::cyan; + break; + case 2: + currentFigure_ = { + {0, 1}, + {0, 1}, + {1, 1} + }; + colorFigure = Qt::magenta; + break; + case 3: + currentFigure_ = { + {1, 0}, + {1, 0}, + {1, 1} + }; + colorFigure = Qt::blue; + break; + case 4: + currentFigure_ = { + {1, 1}, + {1, 1} + }; + colorFigure = Qt::yellow; + break; + case 5: + currentFigure_ = { + {1, 1, 0}, + {0, 1, 1} + }; + colorFigure = Qt::green; + break; + case 6: + currentFigure_ = { + {0, 1, 0}, + {1, 1, 1} + }; + colorFigure = Qt::gray; + break; + case 7: + currentFigure_ = { + {0, 1, 1}, + {1, 1, 0} + }; + colorFigure = Qt::red; + break; + default: + break; + } + + emit FigureSpawned(); +} + +QVector> GameField::GetCurrentFigure() { + return currentFigure_; +} + +QVector> GameField::GetRotateCurrentFigure() { + QVector> currFigure = GetCurrentFigure(); + QVector> RotateFigure; + + RotateFigure.resize(currFigure[0].size()); + + for (int i = 0; i < RotateFigure.size(); ++i) { + RotateFigure[i].resize(currFigure.size()); + } + + + for(int i = 0; i < currFigure.size(); i++) { + for (int j = 0; j < currFigure[0].size(); j++) { + RotateFigure[j][currFigure.size() - i - 1] = currFigure[i][j]; + } + } + + currentFigure_ = RotateFigure; + + emit CurrentFigureChanged(); + return currentFigure_; +} + + +void GameField::updateGameGrid() { + for (int i = 0; i < currentFigure_.size(); ++i) { + for (int j = 0; j < currentFigure_[0].size(); ++j) { + if (currentFigure_[i][j] == 1) { + int x = currentFigureRow_ + i; + int y = currentFigureColumn_ + j; + + CheckLine(); + //CheckColumn(); + GameGrid_[x][y] = 1; + } + } + } +} + +bool GameField::CheckCollision() { + for (int i = 0; i < currentFigure_.size(); i++) { + for (int j = 0; j < currentFigure_[0].size(); j++) { + if (currentFigure_[i][j] == 1) { + int x = currentFigureRow_ + i + 1; + int y = currentFigureColumn_ + j; + + if (x < rowsNumber_ && GameGrid_[x][y] == 1) { + return true; + } + } + } + } + return false; +} + + +bool GameField::CheckCollisionMoveLeft() { + for (int i = 0; i < currentFigure_.size(); i++) { + for (int j = 0; j < currentFigure_[0].size(); j++) { + if (currentFigure_[i][j] == 1) { + int x = currentFigureRow_ + i; + int y = currentFigureColumn_ + j - 1; + + if (y < 0 || (x < rowsNumber_ && GameGrid_[x][y] == 1)) { + return true; + } + } + } + } + return false; +} + +bool GameField::CheckCollisionMoveRight() { + for (int i = 0; i < currentFigure_.size(); i++) { + for (int j = 0; j < currentFigure_[0].size(); j++) { + if (currentFigure_[i][j] == 1) { + int x = currentFigureRow_ + i; + int y = currentFigureColumn_ + j + 1; + + if (y >= columnsNumber_ || (x < rowsNumber_ && GameGrid_[x][y] == 1)) { + return true; + } + } + } + } + return false; +} + +bool GameField::CheckCollisionRotate() { + + for (int i = 0; i < currentFigure_.size(); i++) { + for (int j = 0; j < currentFigure_[0].size(); j++) { + if (currentFigure_[i][j] == 1) { + int x = currentFigureRow_ + i; + int y = currentFigureColumn_ + j; + + if (x >= rowsNumber_ || y < 0 || y >= columnsNumber_ || GameGrid_[x][y] == 1) { + return true; + } + } + } + } + return false; +} + +bool GameField::CheckFullLine(int row) { + for(int j = 0; j < columnsNumber_; j++) { + if(GameGrid_[row][j] != 1) { + return false; + } + } + return true; +} + +bool GameField::CheckFullColumn(int column) { + for (int i = 0; i < rowsNumber_; i++) { + if (GameGrid_[i][column] != 1) { + return false; + } + } + return true; +} + +void GameField::RemoveFullLine(int row) { + for (int j = 0; j < columnsNumber_; j++) { + GameGrid_[row][j] = 0; + } + + for(int k = row;k > 0;k--) { + for(int j = 0;j < columnsNumber_;j++) { + GameGrid_[k][j] = GameGrid_[k-1][j]; + } + } + +} + +int GameField::GetWinPoints() { + return WinPoints; +} + +// Основная функция +void GameField::CheckLine() { + for(int i = rowsNumber_ - 1; i >= 0; i--) { + if (CheckFullLine(i)) { + RemoveFullLine(i); + WinPoints += 100; + emit ChangeWinPoints(); + qDebug() << "Ваши очки = " << WinPoints; + } + } +} + +void GameField::CheckColumn() { + for(int j = columnsNumber_ - 1; j >= 0; j--) { + if (CheckFullColumn(j)) { + //emit GameOver(); + isGameOver = true; + qDebug() << "Заполнен столбец" << j; + } + } +} + +void GameField::moveFigure() { + CheckColumn(); + + if(!isGameOver) { + // Проверка, не касается ли текущая фигура нижней границы поля + if (currentFigureRow_ + currentFigure_.size() < rowsNumber_) { + bool isHaveCollision = CheckCollision(); + + if (isHaveCollision) { + // Если столкнулись с другой фигурой, сохраняем текущую фигуру и спавним новую + qDebug() << "коснулись другую фигуру"; + updateGameGrid(); + spawnNextFigure(); + SetFigurePosition(0, columnsNumber_ / 2); + CheckLine(); + } else { + SetFigurePosition(currentFigureRow_ + 1, currentFigureColumn_); + } + } else { + // Если достигли нижней границы, сохраняем текущую фигуру и спавним новую + qDebug() << "Достигли нижнюю границу"; + updateGameGrid(); + spawnNextFigure(); + SetFigurePosition(0, columnsNumber_ / 2); + CheckLine(); + } + + //qDebug() << "currentFigureRow_ = " << currentFigureRow_; + + update(); + } else { + qDebug() << "Вы проиграли"; + isGameOver = false; + emit GameOver(); + + } + +} + + +uint GameField::GetCurrentFigureRow() { + return currentFigureRow_; +} + +uint GameField::GetCurrentFigureColumn() { + return currentFigureColumn_; +} + +void GameField::clearGameGrid() { + GameGrid_ = QVector>(rowsNumber_, QVector(columnsNumber_, 0)); + + currentFigure_ = QVector>(); + currentFigureRow_ = 0; + currentFigureColumn_ = 0; + + qDebug() << "Поле очищено"; + + update(); +} + +void GameField::SetWinPoints(int points) { + WinPoints = points; + emit ChangeWinPoints(); +} + +void GameField::paintEvent(QPaintEvent *event) { + Q_UNUSED(event); + QPainter painter(this); + + painter.setPen(Qt::black); + + painter.fillRect(rect(), Qt::white); + + + for (int i = 0; i < currentFigure_.size(); ++i) { + for (int j = 0; j < currentFigure_[0].size(); ++j) { + if (currentFigure_[i][j] == 1) { + int x = (currentFigureColumn_ + j) * blockSize; + int y = (currentFigureRow_ + i) * blockSize; + painter.fillRect(x, y, blockSize, blockSize, colorFigure); + } + } + } + + for (int i = 0; i < rowsNumber_;i++) { + for (int j = 0; j < columnsNumber_;j++) { + if (GameGrid_[i][j] == 1) { + int x = j * blockSize; + int y = i * blockSize; + painter.fillRect(x, y, blockSize, blockSize, Qt::blue); + painter.drawRect(j * blockSize, i * blockSize, blockSize, blockSize); + } else { + painter.drawRect(j * blockSize, i * blockSize, blockSize, blockSize); + } + } + } + update(); +} + diff --git a/gamefield.h b/gamefield.h index e36baa8..f809dff 100644 --- a/gamefield.h +++ b/gamefield.h @@ -8,29 +8,86 @@ class GameField : public QWidget { public: explicit GameField(QWidget *parent = nullptr); - Q_PROPERTY(uint rowsNumber READ GetRowsNumber WRITE SetRowsNumber NOTIFY + Q_PROPERTY(uint rowsNumber READ GetRowsNumber WRITE SetRowsNumber NOTIFY RowsNumberChanged FINAL) - Q_PROPERTY(uint columnsNumber READ GetColumnsNumber WRITE SetColumnNumber + Q_PROPERTY(uint columnsNumber READ GetColumnsNumber WRITE SetColumnNumber NOTIFY ColumnsNumberChanged FINAL) signals: - void RowsNumberChanged(); - void ColumnsNumberChanged(); - void InitialisationStarted(); - - private slots: - void SetCells(); + void RowsNumberChanged(); + void ColumnsNumberChanged(); + void FigureSpawned(); + void FigureFalling(); + void CurrentFigureChanged(); + void ChangeWinPoints(); + void GameOver(); public: - uint GetRowsNumber() const; - void SetRowsNumber(uint newRowsNumber); + uint GetRowsNumber() const; + void SetRowsNumber(uint newRowsNumber); + + uint GetColumnsNumber() const; + void SetColumnNumber(uint newColumnsCount); + + void SetFigurePosition(int row, int column); + + void spawnNextFigure(); + void updateGameGrid(); + + bool CheckCollision(); + + bool CheckCollisionMoveLeft(); + bool CheckCollisionMoveRight(); + bool CheckCollisionRotate(); + + QVector> GetCurrentFigure(); + QVector> GetRotateCurrentFigure(); + + bool CheckFullLine(int row); + bool CheckFullColumn(int column); + + + void CheckLine(); + void CheckColumn(); + + void RemoveFullLine(int row); + + int GetWinPoints(); - uint GetColumnsNumber() const; - void SetColumnNumber(uint newColumnsCount); + void moveFigure(); + + uint GetCurrentFigureRow(); + uint GetCurrentFigureColumn(); + + void clearGameGrid(); + void SetWinPoints(int points); + + +protected: + void paintEvent(QPaintEvent *event); private: - uint rowsNumber_ = 0; - uint columnsNumber_ = 0; + uint rowsNumber_ = 0; + uint columnsNumber_ = 0; + int currentRow_ = 0; + QVector> gridGame; + + int blockSize = 30; + + int WinPoints = 0; + + bool isLineFull = true; + bool isGameOver = false; + + QVector> currentFigure_; + + QVector> GameGrid_; // Поле с информацией о заполнении поля фигурами + + uint currentFigureRow_; + uint currentFigureColumn_; + + QColor colorFigure; + }; #endif // GAMEFIELD_H diff --git a/gameoverdialog.cpp b/gameoverdialog.cpp new file mode 100644 index 0000000..139806b --- /dev/null +++ b/gameoverdialog.cpp @@ -0,0 +1,14 @@ +#include "gameoverdialog.h" + +GameOverDialog::GameOverDialog(QWidget *parent) : QDialog{parent} { + QVBoxLayout *layout = new QVBoxLayout(this); + + label = new QLabel("Вы проиграли!", this); + layout->addWidget(label); + + newTryButton = new QPushButton("Попробуйте еще раз!", this); + connect(newTryButton, &QPushButton::clicked, this, &QDialog::accept); + layout->addWidget(newTryButton); + + setLayout(layout); +} diff --git a/gameoverdialog.h b/gameoverdialog.h new file mode 100644 index 0000000..e81116a --- /dev/null +++ b/gameoverdialog.h @@ -0,0 +1,22 @@ +#ifndef GAMEOVERDIALOG_H +#define GAMEOVERDIALOG_H + +#include +#include +#include +#include +#include + +class GameOverDialog : public QDialog { + Q_OBJECT +public: + explicit GameOverDialog(QWidget *parent = nullptr); + +private: + + QPushButton *newTryButton; + QLabel *label; + +}; + +#endif // GAMEOVERDIALOG_H diff --git a/modaldialog.cpp b/modaldialog.cpp new file mode 100644 index 0000000..08f73bc --- /dev/null +++ b/modaldialog.cpp @@ -0,0 +1,14 @@ +#include "modaldialog.h" + +ModalDialog::ModalDialog(QWidget *parent) : QDialog{parent} { + QVBoxLayout *layout = new QVBoxLayout(this); + + label = new QLabel("ИГРА НА ПАУЗЕ", this); + layout->addWidget(label); + + okButton = new QPushButton("ПРОДОЛЖИТЬ", this); + connect(okButton, &QPushButton::clicked, this, &QDialog::accept); + layout->addWidget(okButton); + + setLayout(layout); +} diff --git a/modaldialog.h b/modaldialog.h new file mode 100644 index 0000000..68076f3 --- /dev/null +++ b/modaldialog.h @@ -0,0 +1,22 @@ +#ifndef MODALDIALOG_H +#define MODALDIALOG_H + +#include +#include +#include +#include +#include + +class ModalDialog : public QDialog { + Q_OBJECT +public: + explicit ModalDialog(QWidget *parent = nullptr); + +private: + + QPushButton *okButton; + QLabel *label; + +}; + +#endif // MODALDIALOG_H diff --git a/tetramino.cpp b/tetramino.cpp new file mode 100644 index 0000000..449fbd5 --- /dev/null +++ b/tetramino.cpp @@ -0,0 +1,5 @@ +#include "tetramino.h" + +Tetramino::Tetramino() { + +} diff --git a/tetramino.h b/tetramino.h new file mode 100644 index 0000000..20f62b8 --- /dev/null +++ b/tetramino.h @@ -0,0 +1,14 @@ +#ifndef TETRAMINO_H +#define TETRAMINO_H + + +class Tetramino { +public: + Tetramino(); + + int getShape();//Получаем форму + int getColor();// Получаем цвет фигуры + +}; + +#endif // TETRAMINO_H diff --git a/tetris.cpp b/tetris.cpp index 50cf380..fcdf757 100644 --- a/tetris.cpp +++ b/tetris.cpp @@ -1,9 +1,153 @@ #include "tetris.h" #include "ui_tetris.h" +#include +#include +#include +#include +#include Tetris::Tetris(QWidget *parent) : QMainWindow(parent), ui(new Ui::Tetris) { - ui->setupUi(this); + ui->setupUi(this); + + this->setMinimumSize(1200, 800); + this->setMaximumSize(1200, 800); + + lcdNumber = new QLCDNumber; + lcdNumber->setFixedSize(200,50); + lcdNumber->setDigitCount(6); + lcdNumber->display("000000"); + + + gamefield = new GameField(this); + gamefield->setFixedSize(601,721); + + QLabel *labelPoints = new QLabel; + + labelPoints->setText("привет"); + + QPushButton *newGameButton = new QPushButton("Новая игра"); + + QGridLayout *gridLayout = new QGridLayout; + + gridLayout->addWidget(labelPoints,1, 0); + gridLayout->addWidget(gamefield, 1, 1, Qt::AlignHCenter); + gridLayout->addWidget(lcdNumber, 1, 2, Qt::AlignHCenter); + gridLayout->addWidget(newGameButton, 0, 1, Qt::AlignHCenter); + + setCentralWidget(new QWidget(this)); + centralWidget()->setLayout(gridLayout); + + // Создаем таймер для движения вниз + timer = new QTimer(this); + connect(newGameButton, &QPushButton::clicked, this, &Tetris::startNewGame); + connect(timer, &QTimer::timeout, gamefield, &GameField::moveFigure); + connect(gamefield, &GameField::FigureSpawned, this, &Tetris::restoreBasedInterval); + connect(gamefield, &GameField::CurrentFigureChanged, this, &Tetris::updateGameField); + connect(gamefield, &GameField::ChangeWinPoints, this, &Tetris::updateWinPoints); + connect(gamefield, &GameField::GameOver, this, &Tetris::openEndGameDialog); } Tetris::~Tetris() { delete ui; } + + +void Tetris::updateGameField() { + gamefield->update(); +} + +void Tetris::updateWinPoints() { + int currentCountPoints = gamefield->GetWinPoints(); + + QString newDisplayValue = QString::number(currentCountPoints).rightJustified(lcdNumber->digitCount(), '0'); + lcdNumber->display(newDisplayValue); +} + +void Tetris::restoreBasedInterval() { + if (timer->interval() != 400) { + timer->setInterval(400); + timer->start(); + } +} + +void Tetris::gamePause() { + timer->stop(); + openModalDialog(); +} + +void Tetris::startNewGame() { + timer->stop(); + + gamefield->SetWinPoints(0); + updateWinPoints(); + + gamefield->clearGameGrid(); + gamefield->spawnNextFigure(); + gamefield->SetFigurePosition(0, gamefield->GetColumnsNumber() / 2); + + gamefield->setFocus(); + + timer->start(400); +} + +void Tetris::endGame() { + timer->stop(); + gamefield->clearGameGrid(); +} + +void Tetris::openModalDialog() { + ModalDialog dialog(this); + dialog.exec(); + timer->start(400); +} + + + +void Tetris::openEndGameDialog() { + GameOverDialog dialog(this); + dialog.exec(); + endGame(); +} + +void Tetris::keyPressEvent(QKeyEvent *event) { + int currRow = gamefield->GetCurrentFigureRow(); + int currColumn = gamefield->GetCurrentFigureColumn(); + + if (event->key() == Qt::Key_Space) { + gamePause(); + } + + if (event->key() == Qt::Key_Right) { + if(!gamefield->CheckCollisionMoveRight()) { + gamefield->SetFigurePosition(currRow, currColumn + 1); + } + } + + if (event->key() == Qt::Key_Left) { + if(!gamefield->CheckCollisionMoveLeft()) { + gamefield->SetFigurePosition(currRow, currColumn - 1); + } + } + + if (event->key() == Qt::Key_Down) { + timer->start(10); + } + + if (event->key() == Qt::Key_Up) { + gamefield->GetRotateCurrentFigure(); + + QVector> CurrentFigure = gamefield->GetCurrentFigure(); + + if(!gamefield->CheckCollisionRotate()) { + gamefield->GetCurrentFigure(); + gamefield->update(); + //qDebug() << "Пересечений нет"; + } else { + gamefield->SetFigurePosition(currRow, currColumn - CurrentFigure[0].size() + 1); + gamefield->update(); + //qDebug() << "Пересечения есть"; + //qDebug() << CurrentFigure[0].size(); + } + } +} + + diff --git a/tetris.h b/tetris.h index 1245a26..c84e946 100644 --- a/tetris.h +++ b/tetris.h @@ -2,6 +2,11 @@ #define TETRIS_H #include +#include +#include "gamefield.h" +#include "modaldialog.h" +#include "gameoverdialog.h" +#include QT_BEGIN_NAMESPACE namespace Ui { @@ -16,7 +21,24 @@ class Tetris : public QMainWindow { Tetris(QWidget *parent = nullptr); ~Tetris(); + void gamePause(); + void restoreBasedInterval(); + void updateGameField(); + void updateWinPoints(); + void startNewGame(); + void endGame(); + private: Ui::Tetris *ui; + + QTimer *timer; + GameField *gamefield; + ModalDialog *modaldialog; + QLCDNumber *lcdNumber; + void openModalDialog(); + void openEndGameDialog(); + + void keyPressEvent(QKeyEvent *event); + }; #endif // TETRIS_H From ebf0b12a9b48cd5b13a2013092fb2114c2fe3ea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B0=D0=B4=D0=B8=D0=BC?= <20000805@edu.spbgasu.ru> Date: Tue, 5 Dec 2023 18:43:51 +0300 Subject: [PATCH 2/3] Okhrimenko Tetris v2.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Исправлены замечания. Корректное отображение следующей фигуры, очков и всего что необходимо по заданию. --- TetrisTask.pro | 2 + gamefield.cpp | 262 ++++++++++++----------------------------- gamefield.h | 49 ++++---- gameoverdialog.cpp | 10 +- gameoverdialog.h | 6 +- modaldialog.cpp | 10 +- modaldialog.h | 6 +- nextfiguregamegrid.cpp | 40 +++++++ nextfiguregamegrid.h | 29 +++++ tetramino.cpp | 72 ++++++++++- tetramino.h | 18 ++- tetris.cpp | 150 ++++++++++++----------- tetris.h | 37 +++--- 13 files changed, 363 insertions(+), 328 deletions(-) create mode 100644 nextfiguregamegrid.cpp create mode 100644 nextfiguregamegrid.h diff --git a/TetrisTask.pro b/TetrisTask.pro index 6629c01..279a108 100644 --- a/TetrisTask.pro +++ b/TetrisTask.pro @@ -13,6 +13,7 @@ SOURCES += \ gameoverdialog.cpp \ main.cpp \ modaldialog.cpp \ + nextfiguregamegrid.cpp \ tetramino.cpp \ tetris.cpp @@ -20,6 +21,7 @@ HEADERS += \ gamefield.h \ gameoverdialog.h \ modaldialog.h \ + nextfiguregamegrid.h \ tetramino.h \ tetris.h diff --git a/gamefield.cpp b/gamefield.cpp index b97dc83..06c1748 100644 --- a/gamefield.cpp +++ b/gamefield.cpp @@ -6,10 +6,20 @@ #include #include -GameField::GameField(QWidget *parent) : QWidget{parent} { +GameField::GameField(QWidget *parent) : QWidget(parent) { setStyleSheet("border: 4px solid black;"); - emit InitialisationStarted(); + SetColumnNumber(20); + SetRowsNumber(24); + + gameGrid_ = QVector>(rowsNumber_, QVector(columnsNumber_, 0)); + + currentFigureRow_ = 0; + currentFigureColumn_ = 0; +} + +void GameField::SetNextFigureGrid(QVector> fig) { + nextFigure_ = fig; } uint GameField::GetRowsNumber() const { return rowsNumber_; } @@ -33,77 +43,17 @@ void GameField::SetColumnNumber(uint columnsCount) { } void GameField::SetFigurePosition(int row, int column) { - if (column >= 0 && column + currentFigure_[0].size() <= columnsNumber_ && GameGrid_[row][column] != 1) { + if (column >= 0 && column + currentFigure_[0].size() <= columnsNumber_ && gameGrid_[row][column] != 1) { currentFigureRow_ = row; currentFigureColumn_ = column; } update(); } -void GameField::spawnNextFigure() { - - int randNumb = 1 + rand() % 7; - //int randNumb = 4; - - switch (randNumb) { - case 1: - currentFigure_ = { - {1}, - {1}, - {1}, - {1} - }; - colorFigure = Qt::cyan; - break; - case 2: - currentFigure_ = { - {0, 1}, - {0, 1}, - {1, 1} - }; - colorFigure = Qt::magenta; - break; - case 3: - currentFigure_ = { - {1, 0}, - {1, 0}, - {1, 1} - }; - colorFigure = Qt::blue; - break; - case 4: - currentFigure_ = { - {1, 1}, - {1, 1} - }; - colorFigure = Qt::yellow; - break; - case 5: - currentFigure_ = { - {1, 1, 0}, - {0, 1, 1} - }; - colorFigure = Qt::green; - break; - case 6: - currentFigure_ = { - {0, 1, 0}, - {1, 1, 1} - }; - colorFigure = Qt::gray; - break; - case 7: - currentFigure_ = { - {0, 1, 1}, - {1, 1, 0} - }; - colorFigure = Qt::red; - break; - default: - break; - } - - emit FigureSpawned(); +void GameField::SpawnNextFigure() { + currentFigure_ = nextFigure_; + figureColor_ = Qt::blue; + emit FigureSpawned(); } QVector> GameField::GetCurrentFigure() { @@ -133,30 +83,27 @@ QVector> GameField::GetRotateCurrentFigure() { return currentFigure_; } - -void GameField::updateGameGrid() { +void GameField::UpdateGameGrid() { for (int i = 0; i < currentFigure_.size(); ++i) { for (int j = 0; j < currentFigure_[0].size(); ++j) { if (currentFigure_[i][j] == 1) { int x = currentFigureRow_ + i; int y = currentFigureColumn_ + j; - - CheckLine(); - //CheckColumn(); - GameGrid_[x][y] = 1; + CheckingLine(); + gameGrid_[x][y] = 1; } } } } -bool GameField::CheckCollision() { +bool GameField::HasCollisionMove(int x0, int y0) { for (int i = 0; i < currentFigure_.size(); i++) { for (int j = 0; j < currentFigure_[0].size(); j++) { if (currentFigure_[i][j] == 1) { - int x = currentFigureRow_ + i + 1; - int y = currentFigureColumn_ + j; + int x = currentFigureRow_ + i + x0; + int y = currentFigureColumn_ + j + y0; - if (x < rowsNumber_ && GameGrid_[x][y] == 1) { + if (x < 0 || x >= rowsNumber_ || y < 0 || y >= columnsNumber_ || gameGrid_[x][y] == 1) { return true; } } @@ -165,48 +112,14 @@ bool GameField::CheckCollision() { return false; } - -bool GameField::CheckCollisionMoveLeft() { - for (int i = 0; i < currentFigure_.size(); i++) { - for (int j = 0; j < currentFigure_[0].size(); j++) { - if (currentFigure_[i][j] == 1) { - int x = currentFigureRow_ + i; - int y = currentFigureColumn_ + j - 1; - - if (y < 0 || (x < rowsNumber_ && GameGrid_[x][y] == 1)) { - return true; - } - } - } - } - return false; -} - -bool GameField::CheckCollisionMoveRight() { - for (int i = 0; i < currentFigure_.size(); i++) { - for (int j = 0; j < currentFigure_[0].size(); j++) { - if (currentFigure_[i][j] == 1) { - int x = currentFigureRow_ + i; - int y = currentFigureColumn_ + j + 1; - - if (y >= columnsNumber_ || (x < rowsNumber_ && GameGrid_[x][y] == 1)) { - return true; - } - } - } - } - return false; -} - -bool GameField::CheckCollisionRotate() { - +bool GameField::HasCollisionRotation() { for (int i = 0; i < currentFigure_.size(); i++) { for (int j = 0; j < currentFigure_[0].size(); j++) { if (currentFigure_[i][j] == 1) { int x = currentFigureRow_ + i; int y = currentFigureColumn_ + j; - if (x >= rowsNumber_ || y < 0 || y >= columnsNumber_ || GameGrid_[x][y] == 1) { + if (x >= rowsNumber_ || y < 0 || y >= columnsNumber_ || gameGrid_[x][y] == 1) { return true; } } @@ -215,18 +128,9 @@ bool GameField::CheckCollisionRotate() { return false; } -bool GameField::CheckFullLine(int row) { +bool GameField::HasFullLine(int row) { for(int j = 0; j < columnsNumber_; j++) { - if(GameGrid_[row][j] != 1) { - return false; - } - } - return true; -} - -bool GameField::CheckFullColumn(int column) { - for (int i = 0; i < rowsNumber_; i++) { - if (GameGrid_[i][column] != 1) { + if(gameGrid_[row][j] != 1) { return false; } } @@ -235,82 +139,67 @@ bool GameField::CheckFullColumn(int column) { void GameField::RemoveFullLine(int row) { for (int j = 0; j < columnsNumber_; j++) { - GameGrid_[row][j] = 0; + gameGrid_[row][j] = 0; } for(int k = row;k > 0;k--) { - for(int j = 0;j < columnsNumber_;j++) { - GameGrid_[k][j] = GameGrid_[k-1][j]; + for(int j = 0;j < columnsNumber_; j++) { + gameGrid_[k][j] = gameGrid_[k-1][j]; } } - } int GameField::GetWinPoints() { - return WinPoints; + return winPoints_; } -// Основная функция -void GameField::CheckLine() { +void GameField::CheckingLine() { for(int i = rowsNumber_ - 1; i >= 0; i--) { - if (CheckFullLine(i)) { + if (HasFullLine(i)) { RemoveFullLine(i); - WinPoints += 100; + winPoints_ += 100; emit ChangeWinPoints(); - qDebug() << "Ваши очки = " << WinPoints; - } - } -} - -void GameField::CheckColumn() { - for(int j = columnsNumber_ - 1; j >= 0; j--) { - if (CheckFullColumn(j)) { - //emit GameOver(); - isGameOver = true; - qDebug() << "Заполнен столбец" << j; } } } -void GameField::moveFigure() { - CheckColumn(); +void GameField::MoveFigure() { + GetGameOver(); + int CenterPointX = 2; - if(!isGameOver) { - // Проверка, не касается ли текущая фигура нижней границы поля + if(!isGameOver_) { if (currentFigureRow_ + currentFigure_.size() < rowsNumber_) { - bool isHaveCollision = CheckCollision(); - - if (isHaveCollision) { - // Если столкнулись с другой фигурой, сохраняем текущую фигуру и спавним новую - qDebug() << "коснулись другую фигуру"; - updateGameGrid(); - spawnNextFigure(); - SetFigurePosition(0, columnsNumber_ / 2); - CheckLine(); + bool HasCollision = HasCollisionMove(1, 0); + + + if (HasCollision) { + UpdateGameGrid(); + SpawnNextFigure(); + SetFigurePosition(0, columnsNumber_ / CenterPointX); + CheckingLine(); } else { SetFigurePosition(currentFigureRow_ + 1, currentFigureColumn_); } } else { - // Если достигли нижней границы, сохраняем текущую фигуру и спавним новую - qDebug() << "Достигли нижнюю границу"; - updateGameGrid(); - spawnNextFigure(); - SetFigurePosition(0, columnsNumber_ / 2); - CheckLine(); + UpdateGameGrid(); + SpawnNextFigure(); + SetFigurePosition(0, columnsNumber_ / CenterPointX); + CheckingLine(); } - - //qDebug() << "currentFigureRow_ = " << currentFigureRow_; - update(); } else { - qDebug() << "Вы проиграли"; - isGameOver = false; + isGameOver_ = false; emit GameOver(); - } - } +void GameField::GetGameOver() { + for (int i = 0; i < columnsNumber_; i++) { + if (gameGrid_[0][i] != 0) { + isGameOver_ = true; + } + } +} uint GameField::GetCurrentFigureRow() { return currentFigureRow_; @@ -320,20 +209,18 @@ uint GameField::GetCurrentFigureColumn() { return currentFigureColumn_; } -void GameField::clearGameGrid() { - GameGrid_ = QVector>(rowsNumber_, QVector(columnsNumber_, 0)); +void GameField::ClearGameGrid() { + gameGrid_ = QVector>(rowsNumber_, QVector(columnsNumber_, 0)); currentFigure_ = QVector>(); currentFigureRow_ = 0; currentFigureColumn_ = 0; - qDebug() << "Поле очищено"; - update(); } void GameField::SetWinPoints(int points) { - WinPoints = points; + winPoints_ = points; emit ChangeWinPoints(); } @@ -342,32 +229,29 @@ void GameField::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.setPen(Qt::black); - painter.fillRect(rect(), Qt::white); - for (int i = 0; i < currentFigure_.size(); ++i) { for (int j = 0; j < currentFigure_[0].size(); ++j) { if (currentFigure_[i][j] == 1) { - int x = (currentFigureColumn_ + j) * blockSize; - int y = (currentFigureRow_ + i) * blockSize; - painter.fillRect(x, y, blockSize, blockSize, colorFigure); + int x = (currentFigureColumn_ + j) * blockSize_; + int y = (currentFigureRow_ + i) * blockSize_; + painter.fillRect(x, y, blockSize_, blockSize_, figureColor_); } } } - for (int i = 0; i < rowsNumber_;i++) { - for (int j = 0; j < columnsNumber_;j++) { - if (GameGrid_[i][j] == 1) { - int x = j * blockSize; - int y = i * blockSize; - painter.fillRect(x, y, blockSize, blockSize, Qt::blue); - painter.drawRect(j * blockSize, i * blockSize, blockSize, blockSize); + for (int i = 0; i < rowsNumber_; i++) { + for (int j = 0; j < columnsNumber_; j++) { + if (gameGrid_[i][j] == 1) { + int x = j * blockSize_; + int y = i * blockSize_; + painter.fillRect(x, y, blockSize_, blockSize_, Qt::blue); + painter.drawRect(j * blockSize_, i * blockSize_, blockSize_, blockSize_); } else { - painter.drawRect(j * blockSize, i * blockSize, blockSize, blockSize); + painter.drawRect(j * blockSize_, i * blockSize_, blockSize_, blockSize_); } } } update(); } - diff --git a/gamefield.h b/gamefield.h index f809dff..982eed3 100644 --- a/gamefield.h +++ b/gamefield.h @@ -1,8 +1,13 @@ #ifndef GAMEFIELD_H #define GAMEFIELD_H +#include "tetramino.h" +#include "nextfiguregamegrid.h" + #include +class Tetris; + class GameField : public QWidget { Q_OBJECT public: @@ -23,6 +28,8 @@ class GameField : public QWidget { void GameOver(); public: + void SetNextFigureGrid(QVector> fig); + uint GetRowsNumber() const; void SetRowsNumber(uint newRowsNumber); @@ -31,38 +38,33 @@ class GameField : public QWidget { void SetFigurePosition(int row, int column); - void spawnNextFigure(); - void updateGameGrid(); + void SpawnNextFigure(); + void UpdateGameGrid(); - bool CheckCollision(); + bool HasCollisionMove(int xO, int yO); - bool CheckCollisionMoveLeft(); - bool CheckCollisionMoveRight(); - bool CheckCollisionRotate(); + bool HasCollisionRotation(); QVector> GetCurrentFigure(); QVector> GetRotateCurrentFigure(); - bool CheckFullLine(int row); - bool CheckFullColumn(int column); - - - void CheckLine(); - void CheckColumn(); + bool HasFullLine(int row); + void CheckingLine(); void RemoveFullLine(int row); int GetWinPoints(); - void moveFigure(); + void MoveFigure(); + + void GetGameOver(); uint GetCurrentFigureRow(); uint GetCurrentFigureColumn(); - void clearGameGrid(); + void ClearGameGrid(); void SetWinPoints(int points); - protected: void paintEvent(QPaintEvent *event); @@ -70,24 +72,25 @@ class GameField : public QWidget { uint rowsNumber_ = 0; uint columnsNumber_ = 0; int currentRow_ = 0; - QVector> gridGame; - - int blockSize = 30; - int WinPoints = 0; + int blockSize_ = 30; + int winPoints_ = 0; - bool isLineFull = true; - bool isGameOver = false; + bool isLineFull_ = true; + bool isGameOver_ = false; QVector> currentFigure_; + QVector> nextFigure_; - QVector> GameGrid_; // Поле с информацией о заполнении поля фигурами + QVector> gameGrid_; uint currentFigureRow_; uint currentFigureColumn_; - QColor colorFigure; + QColor figureColor_; + Tetramino *tetraminoGeneratorFirst_; + NextFigureGameGrid *nextGameGrid_; }; #endif // GAMEFIELD_H diff --git a/gameoverdialog.cpp b/gameoverdialog.cpp index 139806b..3dc6c5e 100644 --- a/gameoverdialog.cpp +++ b/gameoverdialog.cpp @@ -3,12 +3,12 @@ GameOverDialog::GameOverDialog(QWidget *parent) : QDialog{parent} { QVBoxLayout *layout = new QVBoxLayout(this); - label = new QLabel("Вы проиграли!", this); - layout->addWidget(label); + label_ = new QLabel("Вы проиграли!", this); + layout->addWidget(label_); - newTryButton = new QPushButton("Попробуйте еще раз!", this); - connect(newTryButton, &QPushButton::clicked, this, &QDialog::accept); - layout->addWidget(newTryButton); + newTryButton_ = new QPushButton("Попробуйте еще раз!", this); + connect(newTryButton_, &QPushButton::clicked, this, &QDialog::accept); + layout->addWidget(newTryButton_); setLayout(layout); } diff --git a/gameoverdialog.h b/gameoverdialog.h index e81116a..8c81738 100644 --- a/gameoverdialog.h +++ b/gameoverdialog.h @@ -13,10 +13,8 @@ class GameOverDialog : public QDialog { explicit GameOverDialog(QWidget *parent = nullptr); private: - - QPushButton *newTryButton; - QLabel *label; - + QPushButton *newTryButton_; + QLabel *label_; }; #endif // GAMEOVERDIALOG_H diff --git a/modaldialog.cpp b/modaldialog.cpp index 08f73bc..5ec046d 100644 --- a/modaldialog.cpp +++ b/modaldialog.cpp @@ -3,12 +3,12 @@ ModalDialog::ModalDialog(QWidget *parent) : QDialog{parent} { QVBoxLayout *layout = new QVBoxLayout(this); - label = new QLabel("ИГРА НА ПАУЗЕ", this); - layout->addWidget(label); + label_ = new QLabel("ИГРА НА ПАУЗЕ", this); + layout->addWidget(label_); - okButton = new QPushButton("ПРОДОЛЖИТЬ", this); - connect(okButton, &QPushButton::clicked, this, &QDialog::accept); - layout->addWidget(okButton); + okButton_ = new QPushButton("ПРОДОЛЖИТЬ", this); + connect(okButton_, &QPushButton::clicked, this, &QDialog::accept); + layout->addWidget(okButton_); setLayout(layout); } diff --git a/modaldialog.h b/modaldialog.h index 68076f3..cbb5e55 100644 --- a/modaldialog.h +++ b/modaldialog.h @@ -13,10 +13,8 @@ class ModalDialog : public QDialog { explicit ModalDialog(QWidget *parent = nullptr); private: - - QPushButton *okButton; - QLabel *label; - + QPushButton *okButton_; + QLabel *label_; }; #endif // MODALDIALOG_H diff --git a/nextfiguregamegrid.cpp b/nextfiguregamegrid.cpp new file mode 100644 index 0000000..03e9807 --- /dev/null +++ b/nextfiguregamegrid.cpp @@ -0,0 +1,40 @@ +#include "nextfiguregamegrid.h" + +NextFigureGameGrid::NextFigureGameGrid(QWidget *parent) : QWidget(parent), blockSize_(30) { + setFixedSize(120, 120); + + tetr_ = new Tetramino(this); + + nextFigure_ = QVector>(); +} + + +void NextFigureGameGrid::SetNextFigure() { + nextFigure_ = tetr_->GetCurrentFigure(); + emit nextFigureChanged(); + update(); +} +QVector> NextFigureGameGrid::GetNextFigure() { + return nextFigure_; +} + +void NextFigureGameGrid::paintEvent(QPaintEvent *event) { + Q_UNUSED(event); + QPainter painter(this); + painter.setPen(Qt::black); + painter.fillRect(rect(), Qt::white); + + for (int i = 0; i < nextFigure_.size(); ++i) { + for (int j = 0; j < nextFigure_[0].size(); ++j) { + if (nextFigure_[i][j] == 1) { + int x = j * blockSize_; + int y = i * blockSize_; + painter.fillRect(x, y, blockSize_, blockSize_, Qt::blue); + painter.drawRect(x, y, blockSize_, blockSize_); + } else { + painter.drawRect(j * blockSize_, i * blockSize_, blockSize_, blockSize_); + } + } + } + update(); +} diff --git a/nextfiguregamegrid.h b/nextfiguregamegrid.h new file mode 100644 index 0000000..1e50a97 --- /dev/null +++ b/nextfiguregamegrid.h @@ -0,0 +1,29 @@ +#ifndef NEXTFIGUREGAMEGRID_H +#define NEXTFIGUREGAMEGRID_H + +#include +#include +#include +#include +#include "tetramino.h" + +class NextFigureGameGrid : public QWidget { + Q_OBJECT +public: + explicit NextFigureGameGrid(QWidget *parent = nullptr); + void SetNextFigure(); + + QVector> GetNextFigure(); +signals: + void nextFigureChanged(); + +protected: + void paintEvent(QPaintEvent *event) override; + +private: + QVector> nextFigure_; + int blockSize_; + + Tetramino *tetr_; +}; +#endif // NEXTFIGUREGAMEGRID_H diff --git a/tetramino.cpp b/tetramino.cpp index 449fbd5..ad8cf5b 100644 --- a/tetramino.cpp +++ b/tetramino.cpp @@ -1,5 +1,75 @@ #include "tetramino.h" -Tetramino::Tetramino() { +Tetramino::Tetramino(QObject *parent) : QObject(parent) {} +Tetramino::~Tetramino() {} + +void Tetramino::SetRandomFigure() { + int randNumb = 1 + rand() % 7; + switch (randNumb) { + case 1: + currentFigure_ = { + {1}, + {1}, + {1}, + {1} + }; + colorFigure_ = Qt::cyan; + break; + case 2: + currentFigure_ = { + {0, 1}, + {0, 1}, + {1, 1} + }; + colorFigure_ = Qt::magenta; + break; + case 3: + currentFigure_ = { + {1, 0}, + {1, 0}, + {1, 1} + }; + colorFigure_ = Qt::blue; + break; + case 4: + currentFigure_ = { + {1, 1}, + {1, 1} + }; + colorFigure_ = Qt::yellow; + break; + case 5: + currentFigure_ = { + {1, 1, 0}, + {0, 1, 1} + }; + colorFigure_ = Qt::green; + break; + case 6: + currentFigure_ = { + {0, 1, 0}, + {1, 1, 1} + }; + colorFigure_ = Qt::gray; + break; + case 7: + currentFigure_ = { + {0, 1, 1}, + {1, 1, 0} + }; + colorFigure_ = Qt::red; + break; + default: + break; + } +} + +QVector> Tetramino::GetCurrentFigure() { + SetRandomFigure(); + return currentFigure_; +} + +QColor Tetramino::GetColorFigure() { + return colorFigure_; } diff --git a/tetramino.h b/tetramino.h index 20f62b8..8a5d811 100644 --- a/tetramino.h +++ b/tetramino.h @@ -1,14 +1,22 @@ #ifndef TETRAMINO_H #define TETRAMINO_H +#include +#include +#include -class Tetramino { +class Tetramino : public QObject { + Q_OBJECT public: - Tetramino(); + explicit Tetramino(QObject *parent = nullptr); + ~Tetramino(); + void SetRandomFigure(); - int getShape();//Получаем форму - int getColor();// Получаем цвет фигуры + QVector> GetCurrentFigure(); + QColor GetColorFigure(); +private: + QVector> currentFigure_; + QColor colorFigure_; }; - #endif // TETRAMINO_H diff --git a/tetris.cpp b/tetris.cpp index fcdf757..0ef3225 100644 --- a/tetris.cpp +++ b/tetris.cpp @@ -10,144 +10,142 @@ Tetris::Tetris(QWidget *parent) : QMainWindow(parent), ui(new Ui::Tetris) { ui->setupUi(this); + baseSpeed_ = 400; + boostSpeed_ = 10; + this->setMinimumSize(1200, 800); this->setMaximumSize(1200, 800); - lcdNumber = new QLCDNumber; - lcdNumber->setFixedSize(200,50); - lcdNumber->setDigitCount(6); - lcdNumber->display("000000"); - - - gamefield = new GameField(this); - gamefield->setFixedSize(601,721); + scoreCounter_ = new QLCDNumber; + scoreCounter_->setFixedSize(200, 50); + scoreCounter_->setDigitCount(6); + scoreCounter_->display("000000"); - QLabel *labelPoints = new QLabel; + nextFigureGrid_ = new NextFigureGameGrid(this); + gamefield_ = new GameField(this); - labelPoints->setText("привет"); + gamefield_->setFixedSize(601, 721); QPushButton *newGameButton = new QPushButton("Новая игра"); QGridLayout *gridLayout = new QGridLayout; - - gridLayout->addWidget(labelPoints,1, 0); - gridLayout->addWidget(gamefield, 1, 1, Qt::AlignHCenter); - gridLayout->addWidget(lcdNumber, 1, 2, Qt::AlignHCenter); + gridLayout->addWidget(nextFigureGrid_, 1, 0, Qt::AlignHCenter); + gridLayout->addWidget(gamefield_, 1, 1, Qt::AlignHCenter); + gridLayout->addWidget(scoreCounter_, 1, 2, Qt::AlignHCenter); gridLayout->addWidget(newGameButton, 0, 1, Qt::AlignHCenter); setCentralWidget(new QWidget(this)); centralWidget()->setLayout(gridLayout); - // Создаем таймер для движения вниз - timer = new QTimer(this); - connect(newGameButton, &QPushButton::clicked, this, &Tetris::startNewGame); - connect(timer, &QTimer::timeout, gamefield, &GameField::moveFigure); - connect(gamefield, &GameField::FigureSpawned, this, &Tetris::restoreBasedInterval); - connect(gamefield, &GameField::CurrentFigureChanged, this, &Tetris::updateGameField); - connect(gamefield, &GameField::ChangeWinPoints, this, &Tetris::updateWinPoints); - connect(gamefield, &GameField::GameOver, this, &Tetris::openEndGameDialog); + timer_ = new QTimer(this); + + connect(newGameButton, &QPushButton::clicked, nextFigureGrid_, &NextFigureGameGrid::SetNextFigure); + connect(newGameButton, &QPushButton::clicked, this, &Tetris::UpdateGameFieldFigure); + connect(newGameButton, &QPushButton::clicked, this, &Tetris::StartNewGame); + connect(gamefield_, &GameField::FigureSpawned, nextFigureGrid_, &NextFigureGameGrid::SetNextFigure); + connect(nextFigureGrid_, &NextFigureGameGrid::nextFigureChanged, this, &Tetris::UpdateGameFieldFigure); + connect(timer_, &QTimer::timeout, gamefield_, &GameField::MoveFigure); + connect(gamefield_, &GameField::FigureSpawned, this, &Tetris::RestoreBasedInterval); + connect(gamefield_, &GameField::CurrentFigureChanged, this, &Tetris::UpdateGameField); + connect(gamefield_, &GameField::ChangeWinPoints, this, &Tetris::UpdateWinPoints); + connect(gamefield_, &GameField::GameOver, this, &Tetris::OpenEndGameDialog); } Tetris::~Tetris() { delete ui; } - -void Tetris::updateGameField() { - gamefield->update(); +void Tetris::UpdateGameField() { + gamefield_->update(); } -void Tetris::updateWinPoints() { - int currentCountPoints = gamefield->GetWinPoints(); +void Tetris::UpdateGameFieldFigure() { + gamefield_->SetNextFigureGrid(nextFigureGrid_->GetNextFigure()); +} - QString newDisplayValue = QString::number(currentCountPoints).rightJustified(lcdNumber->digitCount(), '0'); - lcdNumber->display(newDisplayValue); +void Tetris::UpdateWinPoints() { + int currentCountPoints = gamefield_->GetWinPoints(); + QString newDisplayValue = QString::number(currentCountPoints).rightJustified(scoreCounter_->digitCount(), '0'); + scoreCounter_->display(newDisplayValue); } -void Tetris::restoreBasedInterval() { - if (timer->interval() != 400) { - timer->setInterval(400); - timer->start(); +void Tetris::RestoreBasedInterval() { + if (timer_->interval() != baseSpeed_) { + timer_->setInterval(baseSpeed_); + timer_->start(); } } -void Tetris::gamePause() { - timer->stop(); - openModalDialog(); +void Tetris::GamePause() { + timer_->stop(); + OpenModalDialog(); } -void Tetris::startNewGame() { - timer->stop(); +void Tetris::StartNewGame() { + int CenterPointX = 2; + timer_->stop(); + gamefield_->SetWinPoints(0); + UpdateWinPoints(); - gamefield->SetWinPoints(0); - updateWinPoints(); + gamefield_->ClearGameGrid(); + gamefield_->SpawnNextFigure(); + gamefield_->SetFigurePosition(0, gamefield_->GetColumnsNumber() / CenterPointX); - gamefield->clearGameGrid(); - gamefield->spawnNextFigure(); - gamefield->SetFigurePosition(0, gamefield->GetColumnsNumber() / 2); - - gamefield->setFocus(); - - timer->start(400); + gamefield_->setFocus(); + timer_->start(baseSpeed_); } -void Tetris::endGame() { - timer->stop(); - gamefield->clearGameGrid(); +void Tetris::EndGame() { + timer_->stop(); + gamefield_->ClearGameGrid(); + gamefield_->SetWinPoints(0); } -void Tetris::openModalDialog() { +void Tetris::OpenModalDialog() { ModalDialog dialog(this); dialog.exec(); - timer->start(400); + timer_->start(400); } - - -void Tetris::openEndGameDialog() { +void Tetris::OpenEndGameDialog() { GameOverDialog dialog(this); dialog.exec(); - endGame(); + EndGame(); } void Tetris::keyPressEvent(QKeyEvent *event) { - int currRow = gamefield->GetCurrentFigureRow(); - int currColumn = gamefield->GetCurrentFigureColumn(); + int currRow = gamefield_->GetCurrentFigureRow(); + int currColumn = gamefield_->GetCurrentFigureColumn(); if (event->key() == Qt::Key_Space) { - gamePause(); + GamePause(); } if (event->key() == Qt::Key_Right) { - if(!gamefield->CheckCollisionMoveRight()) { - gamefield->SetFigurePosition(currRow, currColumn + 1); + if(!gamefield_->HasCollisionMove(0, 1)) { + gamefield_->SetFigurePosition(currRow, currColumn + 1); } } if (event->key() == Qt::Key_Left) { - if(!gamefield->CheckCollisionMoveLeft()) { - gamefield->SetFigurePosition(currRow, currColumn - 1); + if(!gamefield_->HasCollisionMove(0, -1)) { + gamefield_->SetFigurePosition(currRow, currColumn - 1); } } if (event->key() == Qt::Key_Down) { - timer->start(10); + timer_->start(boostSpeed_); } if (event->key() == Qt::Key_Up) { - gamefield->GetRotateCurrentFigure(); + gamefield_->GetRotateCurrentFigure(); - QVector> CurrentFigure = gamefield->GetCurrentFigure(); + QVector> CurrentFigure = gamefield_->GetCurrentFigure(); - if(!gamefield->CheckCollisionRotate()) { - gamefield->GetCurrentFigure(); - gamefield->update(); - //qDebug() << "Пересечений нет"; + if(!gamefield_->HasCollisionRotation()) { + gamefield_->GetCurrentFigure(); + gamefield_->update(); } else { - gamefield->SetFigurePosition(currRow, currColumn - CurrentFigure[0].size() + 1); - gamefield->update(); - //qDebug() << "Пересечения есть"; - //qDebug() << CurrentFigure[0].size(); + gamefield_->SetFigurePosition(currRow, currColumn - CurrentFigure[0].size() + 1); + gamefield_->update(); } } } - - diff --git a/tetris.h b/tetris.h index c84e946..3bb481b 100644 --- a/tetris.h +++ b/tetris.h @@ -6,6 +6,8 @@ #include "gamefield.h" #include "modaldialog.h" #include "gameoverdialog.h" +#include "nextfiguregamegrid.h" + #include QT_BEGIN_NAMESPACE @@ -21,24 +23,27 @@ class Tetris : public QMainWindow { Tetris(QWidget *parent = nullptr); ~Tetris(); - void gamePause(); - void restoreBasedInterval(); - void updateGameField(); - void updateWinPoints(); - void startNewGame(); - void endGame(); - - private: - Ui::Tetris *ui; + void GamePause(); + void RestoreBasedInterval(); + void UpdateGameField(); + void UpdateWinPoints(); + void StartNewGame(); + void EndGame(); + void OpenModalDialog(); + void OpenEndGameDialog(); - QTimer *timer; - GameField *gamefield; - ModalDialog *modaldialog; - QLCDNumber *lcdNumber; - void openModalDialog(); - void openEndGameDialog(); +private slots: + void UpdateGameFieldFigure(); +protected: void keyPressEvent(QKeyEvent *event); - +private: + Ui::Tetris *ui; + + int baseSpeed_, boostSpeed_; + QTimer *timer_; + GameField *gamefield_; + QLCDNumber *scoreCounter_; + NextFigureGameGrid *nextFigureGrid_; }; #endif // TETRIS_H From d4520a14d15dad7520ed0f02ed95ee6398b6f2b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B0=D0=B4=D0=B8=D0=BC?= <20000805@edu.spbgasu.ru> Date: Wed, 6 Dec 2023 13:25:22 +0300 Subject: [PATCH 3/3] Tetris v3.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Исправлены замечания --- gamefield.cpp | 9 ++++----- gamefield.h | 2 +- nextfiguregamegrid.cpp | 7 +++---- nextfiguregamegrid.h | 4 ++-- tetramino.cpp | 3 ++- tetris.cpp | 2 +- 6 files changed, 13 insertions(+), 14 deletions(-) diff --git a/gamefield.cpp b/gamefield.cpp index 06c1748..335a16b 100644 --- a/gamefield.cpp +++ b/gamefield.cpp @@ -18,8 +18,8 @@ GameField::GameField(QWidget *parent) : QWidget(parent) { currentFigureColumn_ = 0; } -void GameField::SetNextFigureGrid(QVector> fig) { - nextFigure_ = fig; +void GameField::SetNextFigureGrid(QVector> figure) { + nextFigure_ = figure; } uint GameField::GetRowsNumber() const { return rowsNumber_; } @@ -169,10 +169,9 @@ void GameField::MoveFigure() { if(!isGameOver_) { if (currentFigureRow_ + currentFigure_.size() < rowsNumber_) { - bool HasCollision = HasCollisionMove(1, 0); + bool hasCollision = HasCollisionMove(1, 0); - - if (HasCollision) { + if (hasCollision) { UpdateGameGrid(); SpawnNextFigure(); SetFigurePosition(0, columnsNumber_ / CenterPointX); diff --git a/gamefield.h b/gamefield.h index 982eed3..727c678 100644 --- a/gamefield.h +++ b/gamefield.h @@ -28,7 +28,7 @@ class GameField : public QWidget { void GameOver(); public: - void SetNextFigureGrid(QVector> fig); + void SetNextFigureGrid(QVector> figure); uint GetRowsNumber() const; void SetRowsNumber(uint newRowsNumber); diff --git a/nextfiguregamegrid.cpp b/nextfiguregamegrid.cpp index 03e9807..105676f 100644 --- a/nextfiguregamegrid.cpp +++ b/nextfiguregamegrid.cpp @@ -3,15 +3,14 @@ NextFigureGameGrid::NextFigureGameGrid(QWidget *parent) : QWidget(parent), blockSize_(30) { setFixedSize(120, 120); - tetr_ = new Tetramino(this); + tetramino_ = new Tetramino(this); nextFigure_ = QVector>(); } - void NextFigureGameGrid::SetNextFigure() { - nextFigure_ = tetr_->GetCurrentFigure(); - emit nextFigureChanged(); + nextFigure_ = tetramino_->GetCurrentFigure(); + emit NextFigureChanged(); update(); } QVector> NextFigureGameGrid::GetNextFigure() { diff --git a/nextfiguregamegrid.h b/nextfiguregamegrid.h index 1e50a97..9539f58 100644 --- a/nextfiguregamegrid.h +++ b/nextfiguregamegrid.h @@ -15,7 +15,7 @@ class NextFigureGameGrid : public QWidget { QVector> GetNextFigure(); signals: - void nextFigureChanged(); + void NextFigureChanged(); protected: void paintEvent(QPaintEvent *event) override; @@ -24,6 +24,6 @@ class NextFigureGameGrid : public QWidget { QVector> nextFigure_; int blockSize_; - Tetramino *tetr_; + Tetramino *tetramino_; }; #endif // NEXTFIGUREGAMEGRID_H diff --git a/tetramino.cpp b/tetramino.cpp index ad8cf5b..a63014d 100644 --- a/tetramino.cpp +++ b/tetramino.cpp @@ -5,7 +5,8 @@ Tetramino::Tetramino(QObject *parent) : QObject(parent) {} Tetramino::~Tetramino() {} void Tetramino::SetRandomFigure() { - int randNumb = 1 + rand() % 7; + int countFigures = 7; + int randNumb = 1 + rand() % countFigures; switch (randNumb) { case 1: currentFigure_ = { diff --git a/tetris.cpp b/tetris.cpp index 0ef3225..f53328d 100644 --- a/tetris.cpp +++ b/tetris.cpp @@ -43,7 +43,7 @@ Tetris::Tetris(QWidget *parent) : QMainWindow(parent), ui(new Ui::Tetris) { connect(newGameButton, &QPushButton::clicked, this, &Tetris::UpdateGameFieldFigure); connect(newGameButton, &QPushButton::clicked, this, &Tetris::StartNewGame); connect(gamefield_, &GameField::FigureSpawned, nextFigureGrid_, &NextFigureGameGrid::SetNextFigure); - connect(nextFigureGrid_, &NextFigureGameGrid::nextFigureChanged, this, &Tetris::UpdateGameFieldFigure); + connect(nextFigureGrid_, &NextFigureGameGrid::NextFigureChanged, this, &Tetris::UpdateGameFieldFigure); connect(timer_, &QTimer::timeout, gamefield_, &GameField::MoveFigure); connect(gamefield_, &GameField::FigureSpawned, this, &Tetris::RestoreBasedInterval); connect(gamefield_, &GameField::CurrentFigureChanged, this, &Tetris::UpdateGameField);