一、先看效果图
二、主要的设计思路:
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 0penLine.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;
}
资源下载