Qt5.10编写俄罗斯方块

16 篇文章 2 订阅
本文详细介绍了使用Qt构建俄罗斯方块游戏的过程,包括图形界面绘制、方块类设计、随机生成、历史最高分记录和用户交互。核心类如BaseBlock、BlockFactory和不同类型方块如TBlock、OBlock的实现被逐一剖析。
摘要由CSDN通过智能技术生成

一、先看效果图

在这里插入图片描述

二、主要的设计思路:

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;
}

资源下载

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wb175208

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值