一、先看效果图
二、主要的设计思路:
1.采用Qt的QGraphicsScene、QGraphicsScene、QGraphicsItem实现界面的绘制;
2.对每一种类型的方块单独设计一个类,所有类型的方块都是继承自同一基类;
3.采用Qt的随机数生产机制,随机的生产每一种类型的方块;
4.使用SQLite数据库记录历史的最高值;
5.使用方向按键表示变形和移动方块;
6.主绘图界面和下一个方块的提示界面,分别使用不同的类来表示。
三、主要类
1.不同类型的方块基类:
#pragma once
#include "../TetrisDef.h"
//俄罗斯方块的基类
#include "SubBlock.h"
class QPoint;
class BaseBlock {
public:
BaseBlock(BlockType blockType);
~BaseBlock();
BlockType&getBlockType() {
return _blockType;
}
virtual QColor getBlockColor() {
return QColor(0, 0, 0);
}
virtual QPixmap getPixmap();
//获取每种类型方块的初始形式
virtual void getHeadFirstPattern(QPoint* currentBlock);
//方块变形下一个样式
virtual QPoint* getNextPattern();
virtual void nextPatternEfficient(bool b);//当前生成的样式是否有效
protected:
QPixmap _pixmap;
BlockType _blockType = ERROR_BLOCK;//方块类型
bool** _blockPattern;//方块样式 指的实际的行列位置,而不是实际的像素位置
int _changeID = 0;//变化样式
QPoint* _changeFormula = nullptr;//行列的变化公式
};
#include "BaseBlock.h"
BaseBlock::BaseBlock(BlockType blockType) {
_blockType = blockType;
_blockPattern = new bool*[4];
for (int i = 0;i< 4;i++){
_blockPattern[i] = new bool[4];
for (int j = 0; j < 4; j++) {
_blockPattern[i][j] = false;
}
}
_changeFormula = new QPoint[4];
}
BaseBlock::~BaseBlock() {
}
QPixmap BaseBlock::getPixmap() {
QImage image(QString(":/Tetris/Res/I.png"));
_pixmap = QPixmap::fromImage(image);
return _pixmap;
}
void BaseBlock::getHeadFirstPattern(QPoint* currentBlock) {
}
QPoint* BaseBlock::getNextPattern() {
return _changeFormula;
}
void BaseBlock::nextPatternEfficient(bool b) {
if (!b){//没有生效
_changeID--;
}
}
2.方块工厂类:
#pragma once
#include "../TetrisDef.h"
//方块的生产工厂
class BaseBlock;
class BlockFactory {
public:
BlockFactory();
~BlockFactory();
BaseBlock* createBlock(BlockType type);
};
#include "BlockFactory.h"
#include "BaseBlock.h"
#include "IBlock.h"
#include "JBlock.h"
#include "LBlock.h"
#include "OBlock.h"
#include "SBlock.h"
#include "TBlock.h"
#include "ZBlock.h"
BlockFactory::BlockFactory() {
}
BlockFactory::~BlockFactory() {
}
BaseBlock* BlockFactory::createBlock(BlockType type) {
BaseBlock* block = nullptr;
switch (type)
{
case I_BLOCK:
block = new IBlock;
break;
case J_BLOCK:
block = new JBlock;
break;
case L_BLOCK:
block = new LBlock;
break;
case O_BLOCK:
block = new OBlock;
break;
case S_BLOCK:
block = new SBlock;
break;
case Z_BLOCK:
block = new ZBlock;
break;
case T_BLOCK:
block = new TBlock;
break;
default:
break;
}
return block;
}
3.主要的类型的方块:
T行方块:
#pragma once
#include "BaseBlock.h"
class TBlock :
public BaseBlock {
public:
TBlock();
~TBlock();
QColor getBlockColor()override;
QPixmap getPixmap()override;
void getHeadFirstPattern(QPoint* currentBlock)override;
QPoint* getNextPattern()override;
};
#include "TBlock.h"
#include "SubBlock.h"
TBlock::TBlock() :BaseBlock(T_BLOCK) {
}
TBlock::~TBlock() {
}
QColor TBlock::getBlockColor() {
return QColor(255, 0, 255);
}
QPixmap TBlock::getPixmap() {
QImage image(QString(":/Tetris/Res/T.png"));
_pixmap = QPixmap::fromImage(image);
return _pixmap;
}
void TBlock::getHeadFirstPattern(QPoint* currentBlock) {
currentBlock[0] = QPoint(0, 0);
currentBlock[1] = QPoint(0, 1);
currentBlock[2] = QPoint(0, 2);
currentBlock[3] = QPoint(1, 1);
}
QPoint* TBlock::getNextPattern() {
if (_changeID % 4 == 0) {
_changeFormula[0] = QPoint(0, 2);
_changeFormula[1] = QPoint(1, 1);
_changeFormula[2] = QPoint(2, 0);
_changeFormula[3] = QPoint(0, 0);
} else if (_changeID % 4 == 1) {
_changeFormula[0] = QPoint(2, 0);
_changeFormula[1] = QPoint(1, -1);
_changeFormula[2] = QPoint(0, -2);
_changeFormula[3] = QPoint(0, 0);
} else if (_changeID % 4 == 2) {
_changeFormula[0] = QPoint(0, -2);
_changeFormula[1] = QPoint(-1, -1);
_changeFormula[2] = QPoint(-2, 0);
_changeFormula[3] = QPoint(0, 0);
} else if (_changeID % 4 == 3) {
_changeFormula[0] = QPoint(-2, 0);
_changeFormula[1] = QPoint(-1, 1);
_changeFormula[2] = QPoint(0, 2);
_changeFormula[3] = QPoint(0, 0);
}
_changeID++;
return _changeFormula;
}
O型方块:
#pragma once
#include "BaseBlock.h"
//O
class OBlock :public BaseBlock {
public:
OBlock();
~OBlock();
QColor getBlockColor()override;
QPixmap getPixmap()override;
void getHeadFirstPattern(QPoint* currentBlock)override;
QPoint* getNextPattern()override;
};
#include "OBlock.h"
#include "SubBlock.h"
OBlock::OBlock() :BaseBlock(O_BLOCK){
}
OBlock::~OBlock() {
}
QColor OBlock::getBlockColor() {
return QColor(204, 11, 16);
}
QPixmap OBlock::getPixmap() {
QImage image(QString(":/Tetris/Res/O.png"));
_pixmap = QPixmap::fromImage(image);
return _pixmap;
}
void OBlock::getHeadFirstPattern(QPoint* currentBlock) {
currentBlock[0] = QPoint(0, 0);
currentBlock[1] = QPoint(0, 1);
currentBlock[2] = QPoint(1, 0);
currentBlock[3] = QPoint(1, 1);
}
QPoint* OBlock::getNextPattern() {
_changeFormula[0] = QPoint(0, 0);
_changeFormula[1] = QPoint(0, 0);
_changeFormula[2] = QPoint(0, 0);
_changeFormula[3] = QPoint(0, 0);
return _changeFormula;
}
4.主要运行框架
#pragma once
#include <QRect>
//主界面框架布局展示
#include "MainFrameBlock.h"
#include <QObject>
#include <QTimer>
class QGraphicsScene;
class QGraphicsView;
class BaseBlock;
class QGraphicsRectItem;
class SubBlock;
class ICurrentFinsh;
class QTimer;
class MainFrameLayout :public QObject{
Q_OBJECT
public:
MainFrameLayout(ICurrentFinsh* currentFinish);
~MainFrameLayout();
void initMainGame();
QGraphicsView* getMainFrameView() {
return _mainView;
}
//设置当前正在运动的方块
void setCurrentBlock(BaseBlock* block);
//按照时间运行游戏
void runGame();
void moveLeft();
void moveRight();
void change();
void gameOverPlay();
private slots:
void slotGameOverPlay();
private:
void init();
bool firstBlockSpaceUsage();//第一个进入主界面是否被占用
bool isHitDownBlock();//向下移动是否碰到其他方块
bool isHitLeftBlock();//向左移动是否碰到其他方块
bool isHitRightBlock();//向右移动是否碰到其他方块
bool isCurrentBlock(QPoint pos);//判断某一位置的方块是当前运动方块
bool isGameOver();//是否游戏结束
bool isChangeHit();//方块变化之后,时候发生了碰撞
//游戏结束动画,先刷一遍其他颜色,然后在刷新一点背景色
void playFirstColor();
void playSecondColor();
bool totalScore();//统计行数和分数
private:
ICurrentFinsh* _currentFinish = nullptr;
QGraphicsScene* _mainScene = nullptr;
QGraphicsScene* _mainView = nullptr;
MainFrameBlock _mainBlock[20][10];
QColor _bkColor = Qt::lightGray;
QPoint _current4Block[4], _pre4Block[4];
BaseBlock* _currentBlock = nullptr;
bool _tinyBlock[4][4];//新生成的四个小方块
bool _changePos = false;//当改变方块形状的时候,位置就不在改变
QTimer* _gameOverTimer = nullptr;
int _clearRow = 0;
bool _palyFirst = true;//先刷新其他色
QPixmap* _firstPixmap = nullptr;
QPixmap* _secondPixmap = nullptr;
int _totalRows = 0;//消除的总行数
int _totalScore = 0;//总分数
};
#include "MainFrameLayout.h"
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsLineItem>
#include <set>
#include "../Block/BaseBlock.h"
#include "../Block/SubBlock.h"
#include "../ICurrentFinsh.h"
MainFrameLayout::MainFrameLayout(ICurrentFinsh* currentFinish) {
_currentFinish = currentFinish;
init();
}
MainFrameLayout::~MainFrameLayout() {
}
void MainFrameLayout::initMainGame() {
_totalRows = 0;//消除的总行数
_totalScore = 0;//总分数
//初始化界面
for (int i=0;i< 20;i++){
for (int j = 0; j < 10; j++) {
_mainBlock[i][j].setUse(false);
_mainBlock[i][j].setColor(_bkColor);
_mainBlock[i][j].setPixmap(QPixmap());
}
}
_mainScene->update(-4, -4, 208, 408);
}
void MainFrameLayout::init() {
if (_mainScene == nullptr) {
_mainScene = new QGraphicsScene;
_mainScene->setSceneRect(0, 0, 200, 400);
}
if (_mainView == nullptr) {
_mainView = new QGraphicsView;
_mainView->setBackgroundBrush(_bkColor);
_mainView->setRenderHint(QPainter::Antialiasing);
_mainView->setScene(_mainScene);
}
for (int i = 0; i < 20; i++) {
for (int j = 0; j < 10; j++) {
_mainBlock[i][j].setPos(i, j);
_mainBlock[i][j].setPixelPos(QPointF(j * 20, i * 20));
_mainScene->addItem(&_mainBlock[i][j]);
}
}
QPen penLine;
penLine.setStyle(Qt::SolidLine);
penLine.setColor(Qt::white);
penLine.setWidth(2);
//绘制边界
QGraphicsRectItem* rect = new QGraphicsRectItem(-4, -4, 208, 408);
rect->setPen(penLine);
_mainScene->addItem(rect);
#if 0
penLine.setStyle(Qt::DotLine);
penLine.setColor(Qt::yellow);
//横线
for (int i = 0; i <= 20; i++) {
QGraphicsLineItem* hl1 = new QGraphicsLineItem(0, 20 * i, 200, 20 * i);
hl1->setPen(penLine);
_mainScene->addItem(hl1);
}
//竖线
for (int i = 0; i <= 10; i++) {
QGraphicsLineItem* hl1 = new QGraphicsLineItem(20 * i, 0, 20 * i, 400);
hl1->setPen(penLine);
_mainScene->addItem(hl1);
}
#endif
_gameOverTimer = new QTimer;
connect(_gameOverTimer, SIGNAL(timeout()), this, SLOT(slotGameOverPlay()));
_firstPixmap = new QPixmap(20, 20);
_firstPixmap->fill(Qt::transparent);
QPainter painter1(_firstPixmap);
painter1.setPen(QColor(255, 143, 36));
painter1.setBrush(QColor(53, 39, 182));
painter1.drawRect(0, 0, 20, 20);
_secondPixmap = new QPixmap(20, 20);
_secondPixmap->fill(Qt::transparent);
QPainter painter2(_secondPixmap);
painter2.setPen(Qt::NoPen);
painter2.setBrush(_bkColor);
painter2.drawRect(0, 0, 20, 20);
}
void MainFrameLayout::setCurrentBlock(BaseBlock* block) {
if (block != nullptr) {
block->getHeadFirstPattern(_current4Block);
//生产新的方块
for (int i =0;i< 4;i++){
_current4Block[i] = QPoint(_current4Block[i].x(), _current4Block[i].y() + 3);//移到中间位置
}
//判断当前新生成的方块是已经被占用
bool onTop = false;//是否到达顶格
while (firstBlockSpaceUsage()) {
onTop = true;
for (int i = 0; i < 4; i++) {
_current4Block[i] = QPoint(_current4Block[i].x() -1, _current4Block[i].y());//向上移一格
}
}
if (onTop){
//绘制出当前使用的俄罗斯方块
for (size_t i = 0; i < 4; i++) {
if (_current4Block[i].x() < 0) {//超出主界面的部分直接跳过
continue;
}
_mainBlock[_current4Block[i].x()][_current4Block[i].y()].setUse(true);
_mainBlock[_current4Block[i].x()][_current4Block[i].y()].setColor(_currentBlock->getBlockColor());
}
_mainScene->update();
_currentFinish->gameOver();//游戏结束
return;
}
//把新的方块保存起来
for (int i = 0; i < 4; i++) {
_pre4Block[i] = _current4Block[i];
}
_currentBlock = block;
}
for (size_t i = 0; i < 4; i++) {
_mainBlock[_current4Block[i].x()][_current4Block[i].y()].setUse(true);
_mainBlock[_current4Block[i].x()][_current4Block[i].y()].setColor(_currentBlock->getBlockColor());
_mainBlock[_current4Block[i].x()][_current4Block[i].y()].setPixmap(_currentBlock->getPixmap());
}
_mainScene->update(-4, -4, 208, 408);
}
void MainFrameLayout::runGame() {
if (_changePos ){//正在改变形状,就不在移动方块
return;
}
int row = -1, col = -1;
if (isHitDownBlock()) {//已经碰到其他方块或者底部
totalScore();//统计分数
_currentFinish->currentFinish();//当前已经运行完,可以继续运行下一个方块
return;
}
//去掉上一帧的痕迹
for (size_t i = 0; i < 4; i++) {
_mainBlock[_pre4Block[i].x()][_pre4Block[i].y()].setUse(false);
_mainBlock[_pre4Block[i].x()][_pre4Block[i].y()].setColor(_bkColor);
_mainBlock[_pre4Block[i].x()][_pre4Block[i].y()].setPixmap(QPixmap());
}
//绘制当前帧
for (size_t i = 0; i < 4; i++) {
_current4Block[i] = QPoint(_current4Block[i].x() + 1, _current4Block[i].y() );
_mainBlock[_current4Block[i].x() ][_current4Block[i].y()].setUse(true);
_mainBlock[_current4Block[i].x()][_current4Block[i].y()].setColor(_currentBlock->getBlockColor());
_mainBlock[_current4Block[i].x()][_current4Block[i].y()].setPixmap(_currentBlock->getPixmap());
//保存当前帧
_pre4Block[i] = _current4Block[i];
}
_mainScene->update();
}
void MainFrameLayout::moveLeft() {
if (isHitLeftBlock()) {//不能再向左侧移动
return;
}
//去掉上一帧的痕迹
for (size_t i = 0; i < 4; i++) {
_mainBlock[_pre4Block[i].x()][_pre4Block[i].y()].setUse(false);
_mainBlock[_current4Block[i].x()][_current4Block[i].y()].setColor(_bkColor);
_mainBlock[_current4Block[i].x()][_current4Block[i].y()].setPixmap(QPixmap());
}
int row = -1, col = -1;
for (size_t i = 0; i < 4; i++) {
row = _current4Block[i].x();
col = _current4Block[i].y();
col--;
_current4Block[i] = QPoint(row, col);
_pre4Block[i] = _current4Block[i];
_mainBlock[_current4Block[i].x()][_current4Block[i].y()].setUse(true);
_mainBlock[_current4Block[i].x()][_current4Block[i].y()].setColor(_currentBlock->getBlockColor());
_mainBlock[_current4Block[i].x()][_current4Block[i].y()].setPixmap(_currentBlock->getPixmap());
}
_mainScene->update();
}
void MainFrameLayout::moveRight() {
if (isHitRightBlock()){
return;
}
//去掉上一帧的痕迹
for (size_t i = 0; i < 4; i++) {
_mainBlock[_pre4Block[i].x()][_pre4Block[i].y()].setUse(false);
_mainBlock[_current4Block[i].x()][_current4Block[i].y()].setColor(_bkColor);
_mainBlock[_current4Block[i].x()][_current4Block[i].y()].setPixmap(QPixmap());
}
int row = -1, col = -1;
for (size_t i = 0; i < 4; i++) {
row = _current4Block[i].x();
col = _current4Block[i].y();
col++;
_current4Block[i] = QPoint(row, col);
_pre4Block[i] = _current4Block[i];
_mainBlock[_current4Block[i].x()][_current4Block[i].y()].setUse(true);
_mainBlock[_current4Block[i].x()][_current4Block[i].y()].setColor(_currentBlock->getBlockColor());
_mainBlock[_current4Block[i].x()][_current4Block[i].y()].setPixmap(_currentBlock->getPixmap());
}
_mainScene->update();
}
void MainFrameLayout::change() {
_changePos = true;//开始改变形状
//1.变化之前保存原来的形状
for (int i = 0; i < 4; i++) {
_pre4Block[i] = _current4Block[i];
}
//2.清除原来的形状
for (size_t i = 0; i < 4; i++) {
_mainBlock[_current4Block[i].x()][_current4Block[i].y()].setUse(false);
_mainBlock[_current4Block[i].x()][_current4Block[i].y()].setColor(_bkColor);
_mainBlock[_current4Block[i].x()][_current4Block[i].y()].setPixmap(QPixmap());
}
//3.产生新的形状
QPoint*change = _currentBlock->getNextPattern();
for (int i = 0; i < 4;i++) {
_current4Block[i] += change[i];
}
//4.新的形状没有使用成功
if (isChangeHit()){//变化是否超过了边界
bool bButton = false;//变化之后是否在最低端
for (int i = 0; i < 4; i++) {
if (_current4Block[i].x() > 19) {//大于第19行
bButton = true;
}
}
if (bButton){//变化之后,已经超过了最低端
for (size_t i = 0; i < 4; i++) {//则恢复到原来的状态
_mainBlock[_pre4Block[i].x()][_pre4Block[i].y()].setUse(true);
_mainBlock[_pre4Block[i].x()][_pre4Block[i].y()].setColor(_currentBlock->getBlockColor());
_mainBlock[_pre4Block[i].x()][_pre4Block[i].y()].setPixmap(_currentBlock->getPixmap());
}
}
for (int i = 0; i < 4; i++) {
_current4Block[i] = _pre4Block[i];
}
//方块变形之后没有生效
_currentBlock->nextPatternEfficient(false);
_changePos = false;//改变形状完成
return;
}
//5.新的形状成功使用,绘制当前帧
for (size_t i = 0; i < 4; i++) {
_mainBlock[_current4Block[i].x()][_current4Block[i].y()].setUse(true);
_mainBlock[_current4Block[i].x()][_current4Block[i].y()].setColor(_currentBlock->getBlockColor());
_mainBlock[_current4Block[i].x()][_current4Block[i].y()].setPixmap(_currentBlock->getPixmap());
//保存变化之后的形状
_pre4Block[i] = _current4Block[i];
}
_mainScene->update();
_changePos = false;//改变形状完成
}
void MainFrameLayout::gameOverPlay() {
_gameOverTimer->start(50);
_clearRow = 0;
_palyFirst = true;
}
void MainFrameLayout::slotGameOverPlay() {
if (_palyFirst) {
playFirstColor();
} else {
playSecondColor();
}
_mainScene->update();
}
bool MainFrameLayout::firstBlockSpaceUsage() {
for (int i = 0; i < 4; i++) {
if (_current4Block[i].x() < 0){//超出主界面的部分直接跳过
continue;
}
if (_mainBlock[_current4Block[i].x()][_current4Block[i].y()].getUse()//已经被占用
&& isCurrentBlock(_current4Block[i])){//不是当期运行的方块)
return true;
}
}
return false;
}
bool MainFrameLayout::isHitDownBlock() {
//到达最底部
for (size_t i = 0; i < 4; i++) {
if (_current4Block[i].x() >= 19){
return true;
}
}
//是否触碰到其他方块
for (size_t i = 0; i < 4; i++) {
//下一块的位置
QPoint downBlock = QPoint(_current4Block[i].x() + 1, _current4Block[i].y());
//下一个位置不是当前四个方块中,并且已经存在方块了
if (_mainBlock[downBlock.x()][downBlock.y()].getUse()&& !isCurrentBlock(downBlock)){
return true;
}
}
return false;
}
bool MainFrameLayout::isHitLeftBlock() {
//是否到达左部
for (size_t i = 0; i < 4; i++) {
int col = _current4Block[i].y();
if (col == 0) {//到达左部
return true;
}
}
for (size_t i = 0; i < 4; i++) {
//下一块的位置
QPoint leftBlock = QPoint(_current4Block[i].x() , _current4Block[i].y() -1);
//左一个位置不是当前四个方块中,并且已经存在方块了
if (_mainBlock[leftBlock.x()][leftBlock.y()].getUse() && !isCurrentBlock(leftBlock)) {
return true;
}
}
return false;
}
bool MainFrameLayout::isHitRightBlock() {
//是否到达右部
for (size_t i = 0; i < 4; i++) {
int col = _current4Block[i].y();
if (col == 9) {//到达右部
return true;
}
}
for (size_t i = 0; i < 4; i++) {
//下一块的位置
QPoint rightBlock = QPoint(_current4Block[i].x(), _current4Block[i].y() + 1);
//右一个位置不是当前四个方块中,并且已经存在方块了
if (_mainBlock[rightBlock.x()][rightBlock.y()].getUse() && !isCurrentBlock(rightBlock)) {
return true;
}
}
return false;
}
bool MainFrameLayout::isCurrentBlock(QPoint pos) {
for (size_t i = 0; i < 4; i++) {
if (_current4Block[i] == pos) {
return true;
}
}
return false;
}
bool MainFrameLayout::isGameOver() {
return false;
}
bool MainFrameLayout::isChangeHit() {
//是否超出了边界
for (size_t i = 0; i < 4; i++) {
if (_current4Block[i].x() < 0//小于第0行
|| _current4Block[i].x() > 19//大于第19行
|| _current4Block[i].y() < 0//小于第0列
|| _current4Block[i].y() > 9) {//大于第9列
return true;
}
}
//变化之后,是否占用了其他已经有的方格
if (_mainBlock[_current4Block[0].x()][_current4Block[0].y()].getUse()
|| _mainBlock[_current4Block[1].x()][_current4Block[1].y()].getUse()
|| _mainBlock[_current4Block[2].x()][_current4Block[2].y()].getUse()
|| _mainBlock[_current4Block[3].x()][_current4Block[3].y()].getUse()){
return true;
}
return false;
}
void MainFrameLayout::playFirstColor() {
for (int j = 0; j < 10; j++) {
_mainBlock[_clearRow][j].setUse(false);
_mainBlock[_clearRow][j].setColor(QColor(53, 39, 182));
_mainBlock[_clearRow][j].setPixmap(*_firstPixmap);
}
_clearRow++;
if (_clearRow > 19) {
_palyFirst = false;
_clearRow = 0;
}
}
void MainFrameLayout::playSecondColor() {
for (int j = 0; j < 10; j++) {
_mainBlock[_clearRow][j].setUse(false);
_mainBlock[_clearRow][j].setColor(_bkColor);
_mainBlock[_clearRow][j].setPixmap(*_secondPixmap);
}
_clearRow++;
if (_clearRow > 19) {
_gameOverTimer->stop();
_clearRow = 0;
}
}
bool MainFrameLayout::totalScore() {
std::set <int, std::less<int> > fullRows;//若使用less,则从小到大,若使用greater则从大到小。
//1.记录填满的行的位置
for (size_t i = 0; i < 4; i++) {
int r = _current4Block[i].x();
bool full = true;
for (int j = 0; j < 10; j++) {
if (!_mainBlock[r][j].getUse()){//如果有一个空格,说明整行未充满
full = false;
break;
}
}
if (full){//如果一行全部充满,则保存这个行位置
fullRows.insert(r);
}
}
//2.统计行数和分数
int fullR = fullRows.size();
if (fullR == 0){//没有全满的行数
return false;
}
_totalRows += fullR;
if (fullR == 1){//消除1行
_totalScore += 1;
} else if (fullR == 2) {//消除2行
_totalScore += 3;
} else if (fullR == 3) {//消除3行
_totalScore += 6;
} else if (fullR == 4) {//消除4行
_totalScore += 8;
}
//计算总分和总行数
_currentFinish->getTotal(_totalRows, _totalScore);
//3.重新调整布局,整体向下移动相应的格式
for (auto iter = fullRows.begin(); iter != fullRows.end(); ++iter) {
int r = *iter;
for (int rr = r - 1; rr > 0; rr--) {
bool fullSpace = true;
for (int j = 0; j < 10; j++) {//如果整行都没有方块,则直接返回
if (_mainBlock[rr][j].getUse()) {
fullSpace = false;
break;
}
}
if (fullSpace){
//向下移动一行空白
for (int k = 0; k < 10; k++) {
_mainBlock[rr + 1][k] = _mainBlock[rr][k];//上一行空白行的移动到下一行
}
break;
}
//向下移动一行
for (int k = 0; k < 10; k++) {
_mainBlock[rr + 1][k] = _mainBlock[rr][k];//上一行的移动到下一行
}
}
}
_mainScene->update();
return true;
}
5.随机数生产类
#pragma once
//随机排序类
class RandomNumber {
public:
RandomNumber();
~RandomNumber();
void setMaxNumber(int maxNum);
//获取所有序列
int*getAllRandNumber(int&countNumber);
//获取一个随机数
int getOneRandNumber();
private:
int _maxNumber = -1;//最大的整数
int* _orgNum = nullptr;//初始数组
int* _randNum = nullptr;//随机排序后的数组
};
#include "RandomNumber.h"
#include <cstdlib>
#include<QRandomGenerator>
RandomNumber::RandomNumber() {
}
RandomNumber::~RandomNumber() {
}
void RandomNumber::setMaxNumber(int maxNum) {
_maxNumber = maxNum;
if (_orgNum != nullptr || _randNum != nullptr) {
delete _orgNum;
_orgNum = nullptr;
delete _randNum;
_randNum = nullptr;
}
_orgNum = new int[_maxNumber];
_randNum = new int[_maxNumber];
for (int i = 0; i < _maxNumber; i++) {
_orgNum[i] = i;
_randNum[i] = i;
}
}
int* RandomNumber::getAllRandNumber(int&countNumber) {
countNumber = _maxNumber;
int temp = -1;
int maxRand = _maxNumber;
for (int i = 0; i < _maxNumber; i++) {
//1.随机生成 0 和 maxRand-1之间的整数
int randOne = rand() % maxRand;
//2.把_orgNum的位置randOne的数放到需要排序的数组中
_randNum[i] = _orgNum[randOne];
//3.把_orgNum的位置randOne的数和maxRand-1的位置的数交换
temp = _orgNum[randOne];
_orgNum[randOne] = _orgNum[maxRand - 1];
_orgNum[maxRand - 1] = temp;
//4.缩小随机数的范围
maxRand--;
}
return _randNum;
}
int RandomNumber::getOneRandNumber() {
int temp = -1;
int maxRand = _maxNumber;
for (int i = 0; i < _maxNumber; i++) {
//1.随机生成 0 和 maxRand-1之间的整数
int randNum = QRandomGenerator::global()->bounded(_maxNumber-1);//生成一个0和10之间的整数
//2.把_orgNum的位置randOne的数放到需要排序的数组中
_randNum[i] = _orgNum[randNum];
//3.把_orgNum的位置randOne的数和maxRand-1的位置的数交换
temp = _orgNum[randNum];
_orgNum[randNum] = _orgNum[maxRand - 1];
_orgNum[maxRand - 1] = temp;
//4.缩小随机数的范围
maxRand--;
}
return _randNum[0];
}
6.下一个方块展示界面
#pragma once
//下一个方块类型
class QGraphicsScene;
class QGraphicsView;
class RandomNumber;
class BlockFactory;
class BaseBlock;
class SubBlock;
class NextFrameLayout {
public:
NextFrameLayout();
~NextFrameLayout();
void init();
QGraphicsView* getNextFrameView() {
return _nextView;
}
//生产一个新的方块
BaseBlock* createNewBlock();
//当前运行的方块
BaseBlock* getNexBlock() {
return _nextBaseBlock;
}
private:
QGraphicsScene* _nextScene = nullptr;
QGraphicsView* _nextView = nullptr;
bool _tinyBlock[4][4];//四个小方块
SubBlock* _rectItem = nullptr;
//根据随机数生产不同的俄罗斯方块
BlockFactory* _blockFactory = nullptr;
RandomNumber* _randNumber = nullptr;
BaseBlock* _nextBaseBlock = nullptr;//下一个即将运行的俄罗斯方块
};
#include "NextFrameLayout.h"
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsLineItem>
#include <QGraphicsRectItem>
#include "RandomNumber.h"
#include "../Block/BaseBlock.h"
#include "../Block/BlockFactory.h"
#include "../Block/SubBlock.h"
NextFrameLayout::NextFrameLayout() {
init();
}
NextFrameLayout::~NextFrameLayout() {
}
void NextFrameLayout::init() {
_randNumber = new RandomNumber;
_randNumber->setMaxNumber(7);
_blockFactory = new BlockFactory;
for (int i =0;i< 4;i++){
for (int j = 0;j< 4;j++){
_tinyBlock[i][j] = false;
}
}
if (_nextScene == nullptr) {
_nextScene = new QGraphicsScene;
_nextScene->setSceneRect(0, 0, 80, 80);
}
_rectItem = new SubBlock[4];
for (int i = 0; i < 4; i++) {
_rectItem[i].setVisible(false);
_nextScene->addItem(_rectItem + i);
}
if (_nextView == nullptr) {
_nextView = new QGraphicsView;
_nextView->setBackgroundBrush(Qt::darkGray);
_nextView->setRenderHint(QPainter::Antialiasing);
_nextView->setScene(_nextScene);
}
QPen penLine;
penLine.setStyle(Qt::SolidLine);
penLine.setColor(Qt::white);
penLine.setWidth(2);
//绘制边界
QGraphicsRectItem* rect = new QGraphicsRectItem(-4, -4, 88, 88);
rect->setPen(penLine);
_nextScene->addItem(rect);
penLine.setStyle(Qt::SolidLine);
penLine.setColor(Qt::yellow);
penLine.setWidth(1);
//横线
for (int i = 0; i <= 4; i++) {
QGraphicsLineItem* hl1 = new QGraphicsLineItem(0, 20 * i, 80, 20 * i);
hl1->setPen(penLine);
_nextScene->addItem(hl1);
}
//竖线
for (int i = 0; i <= 4; i++) {
QGraphicsLineItem* hl1 = new QGraphicsLineItem(20 * i, 0, 20 * i, 80);
hl1->setPen(penLine);
_nextScene->addItem(hl1);
}
}
BaseBlock* NextFrameLayout::createNewBlock() {
BaseBlock* block = _blockFactory->createBlock((BlockType)(_randNumber->getOneRandNumber()));
if (block != nullptr) {
QPoint currentBlock[4];
block->getHeadFirstPattern(currentBlock);
QColor color = block->getBlockColor();
for (int i = 0; i < 4;i++) {
_rectItem[i].setVisible(true);
_rectItem[i].setSubColor(color);
}
for (int i = 0; i < 4;i++) {
//根据行列位置计算出像素位置,如第三行实际是像素位置Y值
_rectItem[i].setPos(20 * (currentBlock[i].y() + 1), 20 * currentBlock[i].x());
_nextScene->update();
}
_nextView->update();
}
_nextBaseBlock = block;
return block;
}