求解那种带俄罗斯方块的旋转算法标记到底怎么才算

怎样用C++在控制台中编写俄罗斯方块_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
怎样用C++在控制台中编写俄罗斯方块
&&C++在控制台中编写俄罗斯方块
阅读已结束,下载文档到电脑
想免费下载更多文档?
定制HR最喜欢的简历
下载文档到电脑,方便使用
还剩12页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢2639人阅读
小项目设计日志(4)
声明: 仅个人小记
整个有效项目的文件已经上传csdn:
&&2.效果展示
&&3.主要代码
&&4.开发日志
整个程序的完成花了我不少时间, 有许多知识细节不够清楚,边学边做,断断续续完成的。之前有用C++直接做过一次俄罗斯方块,界面简陋,是在控制台运行的。这次用Qt实现,沿用了之前的总体思想,技术细节有所改动。
2.效果展示
&&刚开始:
开始游戏:
背景界面随着分数进行随机的切换
3.主要代码
项目构架:
**基本单元方块类(Elem):**
#ifndef ELEM_H
#define ELEM_H
#include &QGraphicsObject&
#include &QPainter&
#include &QTime&
enum elemColor {
red, yellow, blue, green, lightBlue, purple,gray,randomColor
const QColor ElemColorArray[] = {
QColor(255,0,0,100),
QColor(255,255,0,100),QColor(0,0,255,100),
QColor(0,255,0,100),QColor(0,255,255,100),QColor(255,0,255,100),
QColor(150,100,100,100)
class Elem : public QGraphicsObject
Elem(QPointF pos = QPointF(0,0), int colorId = elemColor::randomColor, QGraphicsItem *parent = Q_NULLPTR);
void paint(QPainter *painter,const QStyleOptionGraphicsItem *option,QWidget *widget);
QRectF boundingRect() const;
int getCurrentStatus();
void setCurrentStatus(int status);
int colorId;
int currentS
#endif // ELEM_H
**基本单元方块类Elem 实现部分:**
#include "elem.h"
Elem::Elem(QPointF pos,int colorId, QGraphicsItem *parent):QGraphicsObject(parent)
this-&currentStatus = 0;
this-&setPos(this-&mapFromParent(pos));
this-&colorId = colorId;
if (this-&colorId == elemColor::randomColor) {
qsrand(QTime().currentTime().second());
this-&colorId = qrand() % 7;
void Elem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
painter-&drawPixmap(0,0,20,20,QPixmap(":/image/images/box.gif"));
painter-&setBrush(QBrush(ElemColorArray[this-&colorId]));
painter-&setPen(QPen(ElemColorArray[this-&colorId]));
painter-&drawRect(0,0,19,19);
QRectF Elem::boundingRect() const
return QRectF(-0.5,-0.5,21,21);
int Elem::getCurrentStatus()
return this-&currentS
void Elem::setCurrentStatus(int status)
this-&currentStatus =
**形状基类MyShape:**
#ifndef MYSHAPE_H
#define MYSHAPE_H
#include &QGraphicsItemGroup&
#include &QKeyEvent&
#include &QObject&
#include &QTime& // 为了引入 随机数
#include "elem.h"
enum shapeCode {
shapeT,shapeL,shapeMirrorL,shapeSquare,shapeZ,shapeMirrorZ,shapeLine,shapeRandom
enum shapeCoorId {
LeftTop, RightTop,RightBottom,LeftBottom
class MyShape : public QObject,public QGraphicsItemGroup
MyShape(QPoint origin = QPoint(300,40));
QPoint getOrigin();
virtual void rolate();
virtual void rolateBack();
int getCurrentStatus();
protected:
protected:
int currentS
int colorId;
Elem * elem[4];
#endif // MYSHAPE_H
**MyShape实现部分**:
#include "myshape.h"
MyShape::MyShape(QPoint origin)
this-&origin =
this-&setPos(this-&origin);
QPoint MyShape::getOrigin()
return this-&
void MyShape::rolate()
this-&currentStatus = (this-&currentStatus + 90) % 360;
this-&setTransformOriginPoint(20,20);
this-&setRotation(this-&currentStatus);
elem[0]-&setCurrentStatus(this-&currentStatus);
elem[1]-&setCurrentStatus(this-&currentStatus);
elem[2]-&setCurrentStatus(this-&currentStatus);
elem[3]-&setCurrentStatus(this-&currentStatus);
void MyShape::rolateBack()
this-&currentStatus = (this-&currentStatus-90 + 360) % 360;
this-&setTransformOriginPoint(20,20);
this-&setRotation(this-&currentStatus);
elem[0]-&setCurrentStatus(this-&currentStatus);
elem[1]-&setCurrentStatus(this-&currentStatus);
elem[2]-&setCurrentStatus(this-&currentStatus);
elem[3]-&setCurrentStatus(this-&currentStatus);
int MyShape::getCurrentStatus()
return this-&currentS
**各个具体的形状这里我只举例一个ShapeLine类:**
#ifndef SHAPELINE_H
#define SHAPELINE_H
#include "myshape.h"
class ShapeLine : public MyShape
ShapeLine(int currentStatus = 0,QPoint origin = QPoint(300,40),int colorId = elemColor::gray);
virtual void rolate();
#endif // SHAPELINE_H
**ShapeLine类实现部分:**
#include "shapeline.h"
ShapeLine::ShapeLine(int currentStatus, QPoint origin,int colorId) : MyShape(origin)
if (currentStatus % 90 || currentStatus & 0) {
currentStatus = 0;
this-&currentStatus = currentStatus % 180;
qsrand(QTime::currentTime().second());
this-&currentStatus = (qrand() % 2) * 90;
this-&colorId = colorId;
elem[0] = new Elem(QPointF(0,0),this-&colorId,this);
elem[1] = new Elem(QPointF(0,20),this-&colorId,this);
elem[2] = new Elem(QPointF(0,40),this-&colorId,this);
elem[3] = new Elem(QPointF(0,60),this-&colorId,this);
this-&addToGroup(elem[0]);
this-&addToGroup(elem[1]);
this-&addToGroup(elem[2]);
this-&addToGroup(elem[3]);
while (this-&currentStatus != 0) {
this-&rolate();
this-&currentStatus -= 90;
elem[0]-&setCurrentStatus(this-&currentStatus);
elem[1]-&setCurrentStatus(this-&currentStatus);
elem[2]-&setCurrentStatus(this-&currentStatus);
elem[3]-&setCurrentStatus(this-&currentStatus);
void ShapeLine::rolate()
this-&currentStatus = (this-&currentStatus + 90) % 180;
this-&setTransformOriginPoint(20,40);
this-&setRotation(this-&currentStatus);
elem[0]-&setCurrentStatus(this-&currentStatus);
elem[1]-&setCurrentStatus(this-&currentStatus);
elem[2]-&setCurrentStatus(this-&currentStatus);
elem[3]-&setCurrentStatus(this-&currentStatus);
**负责核心操控的Game类:**
#ifndef GAME_H
#define GAME_H
#include &QGraphicsView&
#include &QGraphicsScene&
#include &QGraphicsItem&
#include &QGuiApplication&
#include &QLabel&
#include &QPushButton&
#include "myshape.h"
#include &QTimer&
#include &QList&
#include &QPalette&
#include &QLabel&
#include &QGraphicsWidget&
#include &QMediaPlayer&
#include &QScreen&
#include &QDir&
#include "shapet.h"
#include "shapel.h"
#include "shapemirrorl.h"
#include "shapez.h"
#include "shapemirrorz.h"
#include "shapeline.h"
#include "shapesquare.h"
#include &QVector&
#include &iostream&
#include &QMessageBox&
class Game : public QGraphicsView
void keyPressEvent(QKeyEvent *event);
private slots:
void init();
void startMenu();
bool isShapeColliding();
bool isBorderColliding();
bool moveDownOneStep();
void clearUpAndRenewShape();
void clearShapeWithNoChild();
MyShape * newShape(int shapeId = shapeCode::shapeRandom,int status = -1,QPoint landedPoint = QPoint(300,40));
QRectF getShapeCurrentBoundingRectInScene();
void gameOver();
void setFlag(bool flag);
protected slots:
void timeSlice();
void pause();
void screenShotSlot();
protected:
void mousePressEvent(QMouseEvent * event);
void mouseMoveEvent(QMouseEvent * event);
void mouseReleaseEvent(QMouseEvent *event);
QPoint areaO
QGraphicsItem * leftL
QGraphicsItem * bottomL
QGraphicsItem * rightL
QGraphicsItem * topL
QList&MyShape * & currentS
int currentShapeId;
QVector&QVector&bool&& sceneA
int rowsNumR
int totalNumOfShapesU
QGraphicsTextItem * gradeT
QGraphicsTextItem * gradeN
QGraphicsWidget *
QPushButton * startB
QPushButton * optionB
QPushButton * helpB
QPushButton * exitB
QPushButton * exitButton_1;
QPushButton *
QPushButton * pauseB
QLabel * gameOverL
QLabel * gradeL
bool gameS
QMediaPlayer *
QPoint mousePressP
bool mouseP
QPixmap screenS
QPushButton * screenShotB
#endif // GAME_H
**负责核心操控的Game类的实现部分:**
#include "game.h"
Game::Game()
this-&setWindowFlags(Qt::FramelessWindowHint);
this-&setWindowTitle(QStringLiteral("俄罗斯方块"));
this-&setWindowIcon(QIcon(":/image/images/icon.png"));
this-&setMinimumSize(810,510);
this-&setMaximumSize(810,510);
this-&areaOrigin.setX(200);
this-&areaOrigin.setY(40);
this-&areaWidth = 240;
this-&areaHeight = 400;
QGraphicsScene * scene = new QGraphicsS
this-&setScene(scene);
scene-&setSceneRect(5,5,800,500);
scene-&setBackgroundBrush(QBrush(QPixmap(":/image/images/Tetris_background_1.jpg")));
this-&leftLine = scene-&addLine(this-&areaOrigin.x(),this-&areaOrigin.y(),this-&areaOrigin.x(),this-&areaOrigin.y()+this-&areaHeight,QPen(QBrush(QColor(40,40,120,80)),2));
this-&bottomLine = scene-&addLine(this-&areaOrigin.x(),this-&areaOrigin.y()+this-&areaHeight,this-&areaOrigin.x()+this-&areaWidth,this-&areaOrigin.y()+this-&areaHeight,QPen(QBrush(QColor(40,40,120,80)),2));
this-&rightLine = scene-&addLine(this-&areaOrigin.x()+this-&areaWidth,this-&areaOrigin.y()+this-&areaHeight,this-&areaOrigin.x()+this-&areaWidth,this-&areaOrigin.y(),QPen(QBrush(QColor(40,40,120,80)),2));
this-&topLine = scene-&addLine(this-&areaOrigin.x()+this-&areaWidth,this-&areaOrigin.y(),this-&areaOrigin.x(),this-&areaOrigin.y(),QPen(QBrush(QColor(40,40,120,80)),2));
this-&timer = new QTimer(this);
this-&timer-&start(80);
this-&timer-&stop();
QObject::connect(this-&timer,SIGNAL(timeout()),this,SLOT(timeSlice()));
this-&sceneArray.resize(this-&areaHeight/20);
for (int i = 0; i & this-&sceneArray.size(); i ++)
this-&sceneArray[i].resize(this-&areaWidth/20);
this-&gradeText = scene-&addText(QStringLiteral("得分: "),QFont("Times",22,QFont::Bold));
this-&gradeNumber = scene-&addText(QString::number(0),QFont("Times",22,QFont::Bold));
this-&gradeNumber-&moveBy(600,80);
this-&gradeText-&moveBy(520,80);
this-&pauseButton = new QPushButton(QStringLiteral("暂停"),this);
this-&pauseButton-&move(520,150);
QObject::connect(this-&pauseButton,SIGNAL(clicked(bool)),this,SLOT(pause()));
this-&exitButton_1 = new QPushButton(QStringLiteral("结束"),this);
this-&exitButton_1-&move(520,190);
QObject::connect(this-&exitButton_1,SIGNAL(clicked(bool)),this,SLOT(close()));
this-&replay = new QPushButton(QStringLiteral("重玩"),this);
this-&replay-&move(520,230);
QObject::connect(this-&replay,SIGNAL(clicked(bool)),this,SLOT(init()));
this-&screenShotButton = new QPushButton(QStringLiteral("截图"),this);
this-&screenShotButton-&move(520,270);
QObject::connect(this-&screenShotButton,SIGNAL(clicked(bool)),this,SLOT(screenShotSlot()));
this-&bgm = new QMediaPlayer(this);
this-&startMenu();
void Game::startMenu()
this-&mousePressed = false;
this-&cnt = 0;
this-&pauseButton-&hide();
this-&exitButton_1-&hide();
this-&replay-&hide();
this-&screenShotButton-&hide();
this-&gradeText-&hide();
this-&gradeNumber-&hide();
this-&leftLine-&hide();
this-&bottomLine-&hide();
this-&rightLine-&hide();
this-&topLine-&hide();
QWidget * mask = new QWidget();
mask-&setAutoFillBackground(true);
mask-&setPalette(QPalette(QColor(0,0,0,120)));
mask-&resize(810,510);
this-&mask = (QGraphicsWidget *)this-&scene()-&addWidget(mask);
this-&mask-&setZValue(1);
this-&startButton = new QPushButton("开始",this);
this-&optionButton = new QPushButton("选项",this);
this-&helpButton = new QPushButton("帮助",this);
this-&exitButton = new QPushButton("退出",this);
this-&gameOverLabel = new QLabel("游戏结束",this);
this-&gameOverLabel-&hide();
this-&gameOverLabel-&setGeometry(300,80,150,50);
this-&gameOverLabel-&setFont(QFont("Times",20,QFont::Bold));
this-&gameOverLabel-&setPalette(QPalette(QColor(120,40,20)));
this-&scene()-&addWidget(this-&gameOverLabel);
this-&gradeLabel = new QLabel("得分 : ",this);
this-&gradeLabel-&hide();
this-&gradeLabel-&setGeometry(300,120,150,50);
this-&gradeLabel-&setFont(QFont("Times",20,QFont::Bold));
this-&gradeLabel-&setPalette(QPalette(QColor(120,40,20)));
this-&scene()-&addWidget(this-&gradeLabel);
this-&startButton-&move(350,100);
this-&optionButton-&move(350,150);
this-&helpButton-&move(350,200);
this-&exitButton-&move(350,250);
QObject::connect(startButton,SIGNAL(clicked(bool)),this,SLOT(init()));
QObject::connect(exitButton,SIGNAL(clicked(bool)),this,SLOT(close()));
void Game::init()
this-&mousePressed = false;
this-&bgm-&setMedia(QUrl::fromLocalFile("/home/jacklu/music/Summer.mp3"));
this-&bgm-&play();
QList&MyShape*&::iterator i = this-&currentShapelist.begin();
while (i !=this-&currentShapelist.end()){
this-&scene()-&removeItem(*i);
i = this-&currentShapelist.erase(i);
for (int i = 0; i & this-&sceneArray.size(); i ++)
for (int j = 0; j & this-&sceneArray[i].size(); j ++)
this-&sceneArray[i][j] = false;
this-&gameOverLabel-&hide();
this-&pauseButton-&setEnabled(true);
this-&gameStatus = true;
this-&mask-&hide();
this-&startButton-&hide();
this-&optionButton-&hide();
this-&helpButton-&hide();
this-&exitButton-&hide();
this-&leftLine-&show();
this-&bottomLine-&show();
this-&rightLine-&show();
this-&topLine-&show();
this-&pauseButton-&show();
this-&exitButton_1-&show();
this-&replay-&show();
this-&screenShotButton-&show();
this-&gradeText-&show();
this-&gradeNumber-&show();
this-&totalNumOfShapesUsed=0;
this-&rowsNumRemoves = 0;
this-&grades = 0;
this-&gradeNumber-&setPlainText(QString::number(this-&grades));
this-&myshape = this-&newShape(shapeCode::shapeRandom);
this-&scene()-&addItem(this-&myshape);
this-&timer-&start();
this-&timeCount = 0;
this-&speed = 1;
void Game::keyPressEvent(QKeyEvent *event)
if (!this-&myshape)
if (!this-&gameStatus)
if (event-&key() == Qt::Key_Left) {
this-&setFlag(false);
this-&myshape-&moveBy(-20,0);
if (this-&isBorderColliding() || this-&isShapeColliding()) {
this-&myshape-&moveBy(20,0);
this-&setFlag(true);
else if (event-&key() == Qt::Key_Right) {
this-&setFlag(false);
this-&myshape-&moveBy(20,0);
if (this-&isBorderColliding() || this-&isShapeColliding()) {
this-&myshape-&moveBy(-20,0);
this-&setFlag(true);
else if (event-&key() == Qt::Key_Down) {
for (int i = 0; i & 2; i ++) {
if (!this-&moveDownOneStep())
else if (event-&key() == Qt::Key_Space) {
this-&setFlag(false);
this-&myshape-&rolate();
if (this-&isBorderColliding() || this-&isShapeColliding()) {
this-&myshape-&moveBy(20,0);
if (this-&isBorderColliding() || this-&isShapeColliding()) {
this-&myshape-&moveBy(-40,0);
if (this-&isBorderColliding() || this-&isShapeColliding()) {
if (this-&currentShapeId == shapeCode::shapeLine) {
this-&myshape-&moveBy(-20,0);
if (!(this-&isBorderColliding() || this-&isShapeColliding())) {
this-&myshape-&moveBy(20,0);
this-&myshape-&rolateBack();
this-&setFlag(true);
this-&setFlag(true);
bool Game::isShapeColliding()
foreach (QGraphicsItem * item, this-&myshape-&childItems()) {
switch(this-&myshape-&getCurrentStatus()) {
i = (item-&scenePos().y()-this-&areaOrigin.y())/20;
j = (item-&scenePos().x()-this-&areaOrigin.x())/20;
i = (item-&scenePos().y()-this-&areaOrigin.y())/20;
j = (item-&scenePos().x()-this-&areaOrigin.x())/20-1;
i = (item-&scenePos().y()-this-&areaOrigin.y())/20-1;
j = (item-&scenePos().x()-this-&areaOrigin.x())/20-1;
i = (item-&scenePos().y()-this-&areaOrigin.y())/20-1;
j = (item-&scenePos().x()-this-&areaOrigin.x())/20;
if (this-&sceneArray[i][j])
return true;
return false;
bool Game::isBorderColliding()
QRectF rect = this-&getShapeCurrentBoundingRectInScene();
if ( rect.x() & this-&areaOrigin.x() || (rect.x()+rect.width()) & (this-&areaOrigin.x()+this-&areaWidth) || (rect.y()+rect.height()) & (this-&areaOrigin.y() + this-&areaHeight))
return true;
return false;
bool Game::moveDownOneStep()
this-&setFlag(false);
this-&myshape-&moveBy(0,20);
if (this-&isBorderColliding() || this-&isShapeColliding()) {
this-&myshape-&moveBy(0,-20);
this-&setFlag(true);
this-&clearUpAndRenewShape();
return false;
this-&setFlag(true);
return true;
void Game::clearUpAndRenewShape()
int count = 0;
for (int y = this-&areaOrigin.y()+this-&areaHeight-20; y &= 0; y -= 20) {
QList&QGraphicsItem *& list = this-&scene()-&items(QRectF(this-&areaOrigin.x()-1,y-1,this-&areaWidth+2,22),Qt::ContainsItemShape);
if (list.count() == 0) {
QList&QGraphicsItem *&::iterator i = list.begin();
while (i != list.end()) {
if (!((*i)-&sceneBoundingRect().width() &25)) {
i = list.erase(i);
int rowsForArray = (y-this-&areaOrigin.y())/20;
if (list.count() == (this-&areaWidth/20)) {
for (int k = 0; k & this-&sceneArray[rowsForArray].size(); k ++)
this-&sceneArray[rowsForArray][k] = false;
foreach (QGraphicsItem * item, list) {
this-&scene()-&removeItem(item);
else if (count & 0){
this-&rowsNumRemoves+=
for (int k = 0; k & this-&sceneArray[rowsForArray].size(); k ++) {
this-&sceneArray[rowsForArray+count][k] = this-&sceneArray[rowsForArray][k];
this-&sceneArray[rowsForArray][k] = false;
foreach (QGraphicsItem * item, list) {
Elem * p = (Elem *)
switch(p-&getCurrentStatus()) {
p-&moveBy(0,count*20);
p-&moveBy(count*20,0);
p-&moveBy(0,0-count*20);
p-&moveBy(0-count*20,0);
default: QMessageBox::warning(this,"错误","Here , something wrong in game.cpp"); break;
if (count & 0) {
this-&clearShapeWithNoChild();
qDebug() && "this-&getShapeCurrentBoundingRectInScene.y() " && this-&getShapeCurrentBoundingRectInScene().y() &&
if (this-&getShapeCurrentBoundingRectInScene().y() &= this-&areaOrigin.y()) {
this-&gameOver();
this-&totalNumOfShapesUsed ++;
this-&grades = this-&totalNumOfShapesUsed*5 + this-&rowsNumRemoves*20;
this-&gradeNumber-&setPlainText(QString::number(this-&grades));
if (this-&grades & this-&speed*this-&speed*(100 - this-&speed * 2)) {
if (++(this-&speed) & 10) {
this-&speed--;
QString path(":/image/images/Tetris_background_");
qsrand(QTime().currentTime().second());
path += (QString::number(qrand() % 21 + 1) + ".png");
QPixmap pixmap(path);
this-&scene()-&setBackgroundBrush(QBrush(pixmap));
this-&myshape = this-&newShape(shapeCode::shapeRandom);
this-&scene()-&addItem(this-&myshape);
void Game::clearShapeWithNoChild()
QList&MyShape*&::iterator i = this-&currentShapelist.begin();
while (i !=this-&currentShapelist.end()){
if ((*i)-&childItems().count() == 0) {
this-&scene()-&removeItem(*i);
i = this-&currentShapelist.erase(i);
MyShape * Game::newShape(int shapeId,int status, QPoint landedPoint)
if (shapeId == shapeCode::shapeRandom) {
qsrand(QTime().currentTime().second());
shapeId = qrand() % 7;
this-&currentShapeId = shapeId;
MyShape * newShape = NULL;
switch (shapeId) {
case shapeCode::shapeT:
newShape = new ShapeT(status,landedPoint);
case shapeCode::shapeL :
newShape = new ShapeL(status,landedPoint);
case shapeCode::shapeMirrorL :
newShape = new ShapeMirrorL(status,landedPoint);
case shapeCode::shapeSquare :
newShape = new ShapeSquare(status,landedPoint);
case shapeCode::shapeZ :
newShape = new ShapeZ(status,landedPoint);
case shapeCode::shapeMirrorZ :
newShape = new ShapeMirrorZ(status,landedPoint);
case shapeCode::shapeLine :
newShape = new ShapeLine(status,landedPoint);
this-&currentShapelist.append(newShape);
foreach (QGraphicsItem * item, newShape-&childItems()) {
i = (item-&scenePos().y()-this-&areaOrigin.y())/20;
j = (item-&scenePos().x()-this-&areaOrigin.x())/20;
this-&sceneArray[i][j] = true;
return newS
QRectF Game::getShapeCurrentBoundingRectInScene()
int minX, minY, maxX, maxY;
switch(this-&myshape-&getCurrentStatus()) {
minX = this-&myshape-&scenePos().x();
minY = this-&myshape-&scenePos().y();
maxX = minX + (this-&myshape-&sceneBoundingRect().width()-1);
maxY = minY + (this-&myshape-&sceneBoundingRect().height()-1);
maxX = this-&myshape-&scenePos().x();
minY = this-&myshape-&scenePos().y();
minX = maxX - (this-&myshape-&sceneBoundingRect().width()-1);
maxY = minY + (this-&myshape-&sceneBoundingRect().height()-1);
maxX = this-&myshape-&scenePos().x();
maxY = this-&myshape-&scenePos().y();
minX = maxX - (this-&myshape-&sceneBoundingRect().width()-1);
minY = maxY - (this-&myshape-&sceneBoundingRect().height()-1);
minX = this-&myshape-&scenePos().x();
maxY = this-&myshape-&scenePos().y();
maxX = minX + (this-&myshape-&sceneBoundingRect().width()-1);
minY = maxY - (this-&myshape-&sceneBoundingRect().height()-1);
return QRectF(minX,minY,maxX-minX,maxY-minY);
void Game::gameOver()
this-&myshape = NULL;
this-&timer-&stop();
this-&mask-&show();
this-&gameOverLabel-&show();\
this-&gradeLabel-&setText(QString("得分 : ")+QString::number(this-&grades));
this-&gradeLabel-&show();
this-&pauseButton-&setEnabled(false);
void Game::setFlag(bool flag)
switch(this-&myshape-&getCurrentStatus()) {
foreach (QGraphicsItem * item, this-&myshape-&childItems()) {
i = (item-&scenePos().y()-this-&areaOrigin.y())/20;
j = (item-&scenePos().x()-this-&areaOrigin.x())/20;
this-&sceneArray[i][j] =
foreach (QGraphicsItem * item, this-&myshape-&childItems()) {
i = (item-&scenePos().y()-this-&areaOrigin.y())/20;
j = (item-&scenePos().x()-this-&areaOrigin.x()-20)/20;
this-&sceneArray[i][j] =
foreach (QGraphicsItem * item, this-&myshape-&childItems()) {
i = (item-&scenePos().y()-this-&areaOrigin.y()-20)/20;
j = (item-&scenePos().x()-this-&areaOrigin.x()-20)/20;
this-&sceneArray[i][j] =
foreach (QGraphicsItem * item, this-&myshape-&childItems()) {
i = (item-&scenePos().y()-this-&areaOrigin.y()-20)/20;
j = (item-&scenePos().x()-this-&areaOrigin.x())/20;
this-&sceneArray[i][j] =
default: qDebug() && "Here , setFlag is not certain in game.cpp" && break;
void Game::timeSlice()
if (++(this-&timeCount) == (11-this-&speed)) {
this-&timeCount = 0;
this-&moveDownOneStep();
void Game::pause()
if (this-&gameStatus) {
this-&timer-&stop();
this-&pauseButton-&setText(QStringLiteral("继续"));
this-&gameStatus = false;
this-&timer-&start();
this-&pauseButton-&setText(QStringLiteral("暂停"));
this-&gameStatus = true;
this-&pauseButton-&clearFocus();
void Game::screenShotSlot()
QScreen * screen = QGuiApplication::primaryScreen();
QDir * screenshot = new QD
screenshot-&mkdir("screenshot");
QDir screenshotDir("screenshot");
int cnt = screenshotDir.count();
screen-&grabWindow(this-&winId()).save(QString("screenshot/")+QString::number(cnt-2)+QString(".jpg"),"jpg");
void Game::mousePressEvent(QMouseEvent *event)
if (event-&button() == Qt::LeftButton) {
this-&mousePressed = true;
this-&mousePressPos = event-&pos();
qDebug() && "mouse press pos " && event-&pos() ;
qDebug() && "global pos : " && this-&pos() ;
void Game::mouseMoveEvent(QMouseEvent *event)
if (this-&mousePressed) {
if (this-&cnt ++ == 10) {
this-&move((this-&pos()+=(event-&pos()-=this-&mousePressPos)));
this-&cnt = 0;
void Game::mouseReleaseEvent(QMouseEvent *event)
this-&mousePressed = false;
4.开发日志
遇到问题,就是冲突检测
collidingItems()
的问题,估计是我理解的不够全面,现在我得把画边界的矩形线改成一条一条直线来画
估计真的是我没有理解,我感觉Qt提供的冲突检测很傻,我决定还是自己亲自来解决冲突检测的问题
关于冲突检测,我又想了想,我们不能把边界交界的情况视为冲突,因为边界交界的情况太多了,不如俄罗斯方库中的直线,在下降的过程中,如果遇到凹槽,那么,该竖线的冲突会增加,增加,再增加,这样冲突的数量不稳定,我们不好加以判断是否可以在方向上可以移动。 改进: 不以边界为判度断依据,而是以交融的方块为依据,即改组是否有成员方块和其他方块交融
冲突检测的目的就是实现“移动预判”
分析: 整个范围内存在的 QGraphicsItem 除了边界是直线打出来的,其他的都会是方块,故而,暂时不考虑边界,如果发生冲突情况,必然是有方块交融的现象产生,所以,我们预判是否会发生方块交融,从而明定该方向是否生效
或许我可以该一该游戏的规则,比如游戏界面宽度为15个小方块,而我们只要达到某一行10个方块,那么就可以执行消除
08:35 对自定义的Shape类的使用有问题,Shape 继承自 QGraphicsItemGroup
error: ‘staticMetaObject’ is not a member of ‘QGraphicsItemGroup’
{ &QGraphicsItemGroup::staticMetaObject, qt_meta_stringdata_MyShape.data,
解决方法:使得该类 继承自 QObject
同时加上头文件 #include
冲突问题: 目前方块之间的冲突解决,采用 Qt::containsBoundingRect
表示必须外接矩形重合,根据现在的情况,我们设计的每一个形状都必须是有基本单位方块组成,而我们的冲突检测的实质是基本单位方块冲突检测
时间 11:09 我把冲突检测加入到Shape类中,这一设计和我之前用C++在控制台上设计的理念是相违背的,因为我当时认为冲突检测不应该属于Shape的一个能力,一个shape所拥有的不就是应该是 形状的定义,上下左右移动,变形 这三项。我突然觉得,还应该是按照以前的理念设计,当时的理念很合理,Qt这边也是可以实现的
时间 11:18 我个人认为我参考的那份俄罗斯方块代码的类方面的设计没有我的好,尤其是刚刚提及到的这个概念
时间 12:50 问题来了,怎么判定方块和边界的直线冲突?解决方案: 配合方块的外界矩形明定长宽,以及方块的当前位置坐标,得到当前方块的上下左右边界。得到的边界数据配合已经固定的方块活动区域边界的值,我们可以判断出是否出界
时间 16:25 有这么一个概念涌入,即一个任意一个item的入场位置为该item的坐标原点,暂时我还不知道如何切换该item的坐标系
时间 16:45 注意点
boundingRect 外接矩形的长宽都会因为边界线条而增加两个0.5, 比如 一个item设定为 (10,10,20,30) 那么它的外界矩的长宽为 21,31
时间 17:01 本次设计中的冲突分两类:
1.与边界冲突
2.基本单位方块之间的冲突
时间 17:05 用户的操控 只能是 左右以及向下移动
时间 18:33 设置各个方块形态的时候,注意不要用到坐标 减法
(我在 反 L 形状设置的时候就使用了减法,这引发边界冲突判度出错,还是和坐标有关系,这里不好多讲,以后遇到也能推出来)
时间: 20:34 现在要做的是决定什么时候产生下一个方块
时间 : 20:37 我把向下移动的代码单独的写成一个函数, 因为别的地方也用到向下移动,之前的只是用于键盘按下向下键生效,现在我们需要让方块自己下落,同样用到向下移动的代码
时间: 21:32
判断消除 和
时间: 10/04 10:24 我觉得,虽说Qt直接提供了旋转函数,但是那个是纯粹的旋转,并不很好的适合本次俄罗斯方块的设计,因为方块的基本单位长度为 10,而使用旋转函数会不便
时间: 11:19 关于旋转,我不想使用Qt自带的旋转,我决定自己一个一个写(我写的旋转并非严格按照某固定中心旋转)
关于旋转,分两步骤: 1. 设置旋转中心点 setTransformOriginPoint(x,y)
2.指定旋转角度 setRolation(angle)
需要注意的是,旋转也需要冲突预判
考虑到每个形状旋转时候的中心点不同,我觉得这是每个形状的个性,我以前的方案是为每个形状设计单独的类,当然,它们都继承自形状类,这样可以张扬个性。但,我得要写7个类,我想了想,不是我偷懒,而是设计过程中的取舍问题。 我想到,不采用这种方案。我计划着写一个 getRolationPoint(shapeId) 根据shapeId 来或者该形状的旋转中心点,这样是我觉得不错的方法。由此可见,在类的设计过程中,子类的单独彰显 适巧 也是可以较好的融于同一个父类当中
时间:14:11 坐标系问题
时间: 22:18 对坐标系一番研究,发现,原来,item, scene, view 各自拥有坐标系,我们使用坐标时候要统一坐标系。另外,以某个点为中心旋转,旋转的item真个坐标系发生旋转,它的原点同步旋转过去,所以,原点坐标值发生改变,按照新的坐标系重新绘制各个成员
时间: 22:29 场景中的每个item有场景位置(QGraphicsItem::scenePos())与包围矩形(QGraphicsItem::sceneBoundingRect()), 另外,每个item都有本地位置(QGraphicsItem::pos)与包围矩形(QGraphicsItem::boundingRect())
当我们移动 item时候,会发现,场景位置的值才是真实反映了item的移动,而本地位置值保持不变
时间 10/05 13:08 如果没有实施旋转,或者缩放等,只是移动了组内成员的位置,sceneBoundingRect() 不发生变化
时间 20:42 消除部分,我使用 item(QRectF(x,y,w,h),Qt::ContainItemShape) 来获取 y 行的item个数。出了一个问题,就是,最下面的以行始终多一个item,我很纳闷,最后发现原来是下边界的那条直线item 被算进去了。
时间 21:13 紧接着的就是如何消除 item的问题了 ,目前,不考虑使用QGraphicsObject 作为基本元素,我看到网上有借助QGraphicsObject::deleteLater() 来实现删除,而QGraphicsItem 中没有这个函数。
我又在QGraphicsScene类 中看到
removeItem 函数,我试一下,删除的效果是有的,目前看上去好像是能满足我的需求。先试用它
时间 22:30 尴尬了,出现问题了,第一个形状完好落下,然后后来的方块就落不下来了
时间 23:12 原因出在 只是方形形状会有这样的现象,因为方形形状类的代码有小问题,即 currentStatus 没有知名,而 isBorderColliding 中又用到 currentStatus,故而引发了问题
时间 23:50 真是有意思,有出现了一个问题,我想明白了为什么。 shapeLine 就是形状为直线的那个,真是特殊性,特殊在它是一条直线,不跨行。 因为我的消除判断是针对某一行,使用一个“行矩形” QList’&’QGraphicsItem *& list = this-&scene()-&items(QRectF(this-&areaOrigin.x()-1,y-1,this-&areaWidth+2,22),Qt::ContainsItemShape);,包含在该行矩形中的 item 都作数,而我不希望 组item 也作数,只是希望 基本单位方块item作数,之前没有细细思考,以为所有的形状都是跨行的,只要限制了 “行矩形”的高度,就不可能把一个 组item 包含在内。而实际上, shapeLine 是可以被包含在我提供的”行矩形中的”。 这就是为什么 一个 方形方块, 两条直线横放 就会引发消除(1+ 2 + (4 + 1) + (4 + 1) = 13)。
所以,该怎么解决呢??? 我现在严重怀疑网上我参考的那一份俄罗斯方块的代码有很多bug
时间 13:07 今天要做的,一,解决昨天留下的bug,二,给方块上色,图案,三,背景图案
时间 14:44 问题真是接踵而至,没有一个顺畅的
时间 15:21 提及一个知识点: qt 中删除一个对象时候,一,删除掉该对象的所有孩子,二,将自己从父对象的孩子链表中删除,三,删除自己
时间 15:41 考虑到 形状的回收问题,因为,我们删除的是面向一个一个小的基本单位方块,如果只这样,一个形状的孩子都被删除了,这是一个无用的形状,但是没有被删除,占用着内存,同时也可能带来其他的问题(比如shapeLine 的横向放置作数的问题)
。 针对这个问题,我设立了一个currentShapeList 来记录所有当前还有孩子的形状,如果该形状的孩子个数为0,那么即刻删除。
时间16:03 目前看上去,我额外设立的currentShapeList 有良好的效果
时间 16:13 闭着眼睛都知道,肯定还会有bug
时间: 17:13 基本逻辑试行通过,下面就是上色
时间: 18:10 有是一个坐标系问题, 当有行消除,该行上面的方块要下降,我使用item-&move(0,count*20) 出问题了,看上去是下降的行为,但是,这个只是在item自己的坐标系中下降,在scene中有时并不是下降
解决方法: item-&move(0,count*20)更换为 item-&setPos(item-&mapFromScene(item-&scenePos().x(),item-&scenePos().y()+count*20));
时间 19:31 void init(); // 需要写一个初始化函数,明明已经有了构造函数,构造函数不久可一实现初始化吗,为什么还要重写一个init函数呢? 因为游戏会重新开局!!这个重新开局不是关闭游戏再重新打开游戏,而构造函数在整个过程中只是会执行一次,除非关闭程序重新运行才可以执行构造函数,显然着不符合用户需求,用户希望的是在不需要重新打开游戏的前提下,重新游戏
时间: 19:34 心得,如果你尝试着模仿别人做的东西,很多时候,你乍一看会有很多不能够理解的地方,为什么他这样做,为什么他那样做,为什么这样多此一举,我想说的是,一个东西做出来,在基本逻辑完好之后,大体的逻辑会很大幅度的修改,这些修改多是考虑到实际或代码设计的情况。而这些情况,你在一开始的时候顾及不到,也是没有那个精力去想到,因为不是整个东西的主线。你要做的是,自己心里构思,该怎么做,你认为应该是怎样的,然后参考着别人做的东西。这个过程你会发现你需要一直修改,因为在这个过程中你才会遇到各种问题,你需要为这些问题对代码进行修改。很多的修改之后,可能发现自己修改出的东西和别人做好的东西很相似。这是一个由内到外的过程,你对这个东西掌握力会很强。
时间: 下面应该做的是 “上色” ,但是我想先把 旋转时候 出现 靠边旋转不了的情况解决,其实这个问题还是有点小复杂的
时间: 23:20 出了问题,找了好长时间。case 0: …; case 90: …; case 180: …; case 270: …; 我一昧的认为没有其他的情况,实际上存在,比如rolateBack的时候,出现-90,这时候就出现了问题了,我的数据就不是可控的数据,从而导致了bug的产生
时间: 今天的任务: 1. 上色
2.增加自定义形状 3.写博客总结\
时间: 16:05 出现bug,上色的形状的方块冲突检测失效
时间 23:05 心碎一地,我不知道问什么包含性冲突不发生。
23:00 都过了一个月了,这些天里,零零散散的对这个小项目进行改进。 对于形状冲突检测问题,前些日子,我直接摈弃使用colliding函数,自己使用后台数组来实现,即用一个数组来记录当前游戏的状态,所有位置的状态
各种新问题来,我也是很蛋疼。 程序编译时候会直接卡死电脑,我最不爽的就是强制重启电脑了。 而且最近重启电脑都是输命令进入系统的。 还有就是 编码问题,以前一直都是好好的,现在,,一转到windows8.1上就出毛病,编码统统有问题。 现在我想做的是,不是我想,而是windows8.1 下的那个边框真是太太太难看了,所以我决定把边框去掉(因为暂时还不会处理边框,索性直接消除掉),引进的新问题就是,我需要重新实现以下窗口的移动问题。
现象,鼠标拖动过程,框体发生抖动现象,因为鼠标每移动一个像素点 整个框体都要执行一次移动,这样导致框口拖动过程中的抖动现象的产生
现在我引入一个 cnt 变量来控制使得每移动10个像素点才会执行一次真正的移动, 显然有很好的效果
时间 11/18 00:16 想到增加一个功能, 游戏截屏功能
刚刚室友被我拉过来玩了一会儿,怎么说呢,他不是玩的很短的时间,这呵呵,怎么说呢,我觉得,不知道到底是什么情况,我是感受到一点点的尊重,自己做的的东西别人在使用,不是那种很随意对待,很不屑对待的那种。 额,不多扯。
相关的Qt小记:
7& 给应用程序加图标,很简单 使用this-&setWindowIcon(QIcon(“:/image/icon.png”)); 就是引入资源文件里的图片就好了
8& linux下程序转移到 windows下 源码中的中文在编译期间提示 “常量中有换行符”
而且之前中文一直显示乱码,
有这么一个方法,暂时就记着有这么个方法吧
编辑-&select Encode
同时, QStringLiteral(“我是中文”)
对于这个方法,额,我不想多说什么,反正奏效了
9& 今天晚上还仿佛解决了一个问题, 额, 就是之前添加了资源文件之后就会发生编译卡顿的问题,之前是因为长时间的卡顿,我忍受不了就直接强制关机,重启,很不爽的行为。
今天,正好没什么额外的事情,编译又卡住了,我就没有去搭理,过了好一会,我突然发现,它竟然编译好了。 呵呵。所以,目前的解决方法,就是“等”(可能是资源文件有点大)
&&内容有点多,有点小尴尬。提供代码仅供参考,代码中也有相应的注释,关于代码编写过程的思路,在我的日志部分多有体现。有些地方,可能看起来费解,因为往往那些代码并不是我的最初想法,而是在后期开发过程中考虑到种种事先没有考虑到的地方,然后对其进行修改。
By Jack Lu
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:36410次
排名:千里之外
原创:45篇
(3)(5)(3)(4)(1)(2)(4)(2)(5)(5)(2)(1)(1)(3)(5)
(window.slotbydup = window.slotbydup || []).push({
id: '4740881',
container: s,
size: '200,200',
display: 'inlay-fix'}

我要回帖

更多关于 俄罗斯方块消除算法 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信