小游戏:俄罗斯方块

  • 游戏介绍
  • 过程
    • 设计思路
    • 实现过程
      • 1、Block类
      • 2、Tetris类
      • 3、Box类
      • 4、NextBox类
      • 5、MainWindow类
      • 6、main函数
  • 结果
  • 分析
    • 遇到的问题
    • 心得体会
    • 英文文献
    • 对软件维护的认识
  • 源代码
    • 1、Block类
      • block.h
      • block.cpp
    • 2、Tetris类
      • tetris.h
      • tetris.cpp
    • 3、Box类
      • box.h
      • box.cpp
    • 4、NextBox类
      • nextbox.h
      • nextbox.cpp
    • 5、MainWindow类
      • mainwindow.h
      • mainwindow.cpp
    • 6、main函数
      • main.cpp

游戏介绍

小游戏所使用的语言为C++,所选择的环境为Qt 5.9.8。
       如左图所示,这是我设计的俄罗斯方块游戏的开始界面。开始时页面静止,需要按键盘的Space键才能开始游戏。界面左侧为20*10的游戏空间,并且画出网格,方便玩家识别出该图形所在行数和列数。界面右侧有下一个出现的图形,方便玩家思考下一个图形存放的位置。游戏默认从得分为0分、等级为1和下落速度为1000ms开始。此外,下方还有按键提示,方便玩家阅读——按Left(Right)方块左(右)移,按Down加速下移,Esc退出游戏,F5重新开始游戏;按键盘Space使游戏开始,如中间图所示。每种图形有不同的颜色,直至不能下落图形颜色变为白色,而且图形下落可以看到即将落到的最下方位置,有助于提高玩家的游戏体验。此外,按Space键还可以暂停游戏并且标题改为PAUSE!,使游戏更具人性。消除n行得到n*n分,随着得分每增加10分,等级增加1级,图形下落速度加快100毫秒,当速度变为200毫秒时不再加快(再快就玩不下去了);当图形堆叠到游戏区域最顶端时,游戏结束,如右图所示,并出现提示框显示玩家分数和等级。关闭提示框,再按Space键时游戏重新开始。

过程

设计思路

我设计了Block类、Tetris类、Box类、NextBox类和MainWindow类这五个类。其中:Block类用来存储每种图形的信息,用id来区分图形的种类——x[4],y[4]分别用来存储每个图形四个方格的初始横纵坐标,id用来存储图形的种类,centerX和centerY分别用来存储图形的初始中心横纵坐标,color用来存储这种图形的颜色;然后Tetris类用来存储一次游戏中的信息——block用来存储正在移动中的图形的信息,nextBlock用来存储下一出现的图形的信息,shadowBlock用来存储图形即将落到的最下方位置,box[10][20]用来存储游戏区间已有方格的位置,score用来存储分数,level用来存储等级;然后Box类继承QWidget类(空窗口类)用来显示游戏的方块;NextBox类继承QWidge类用来显示下一个方块;最后MainWindow类继承于QMainWindow类(主窗口类)用来整合box、nextbox和控制提示和分数的显示用的QLabel控件。
       程序模块结构图:

实现过程

1、Block类

Block类中含有Block()构造函数,创造图形类型的create()函数,数据清空的clear()函数,以及设置(set)和获取(get)私有成员信息的各种set和get函数。

  • 其中create()函数实现如下图所示:

2、Tetris类

Tetris类中有Tetris()构造函数,初始化init()函数,创造当前图形的createBlock()函数,创造下一个图形的createNextBlock()函数,创造当前位置图形即将落到最下方位置的图形的createShadowBlock()函数,判断图形是否能向右移动dx格、向下移动dy格(若能则图形移动)的move(int dx, int dy)函数,判断是否能向左移动1格(若能,则图形移动)的moveLeft()函数,判断是否能向右移动1格(若能,则图形移动)的moveRight()函数,判断是否能向下移动1格(若能,则图形移动)的moveDown()函数,判断图形能否旋转(若能,则图形显示旋转)的rotate()函数,判断游戏是否结束的gameOver()函数,得到第一行方格都被填满的行的getLine()函数,消除满行的killLines()函数,以及获取(get)私有成员信息的各种get函数。

  • init()函数的实现如下图所示:
  • createBlock()函数的实现如下图所示:
  • createShadowBlock()函数的实现如下图所示:
  • move(int dx, int dy)函数的实现如下图所示:
  • moveDown()函数的实现如下图所示:
  • rotate()函数的实现如下图所示:
  • gameOver()函数的实现如下图所示:
  • getLine()函数的实现如下图所示:
  • killLines()函数的实现如下图所示:

3、Box类

Box类继承于Qt自带的QWidget类,含有Box(QWidget *parent = nullptr)构造函数,更新游戏框内数据和视图的updateTetris(Tetris tetris)函数,绘制游戏运行框内视图的paintEvent(QPaintEvent *event)函数。

  • updateTetris(Tetris tetris)函数的实现如下图所示:
  • paintEvent(QPaintEvent *event)函数的实现如下图所示:

4、NextBox类

NextBox类继承于Qt自带的QWidget类,含有NextBox(QWidget *parent = nullptr)构造函数,更新“下一个图形”框内的数据和视图的updateNextTetris(Tetris tetris)函数,绘制“下一个图形”框内视图的paintEvent(QPaintEvent *event)函数。

  • updateNextTetris(Tetris tetris)函数的实现如下图所示:
  • paintEvent(QPaintEvent *event)函数的实现如下图所示:

5、MainWindow类

MainWindow类继承于Qt自带的QMainWindow类,含有用来构造初始游戏界的面MainWindow(QWidget *parent = 0)构造函数,~MainWindow()析构函数,响应键盘事件的keyPressEvent(QKeyEvent *event)函数,更新分数的updateScore()函数、更新等级的updataeLevel()函数,用来设置时间的onTimer()槽函数。

  • keyPressEvent(QKeyEvent *event)函数的实现如下图所示:
  • onTimer()函数的实现如下图所示:
  • updateScore()函数的实现如下图所示:
  • updateLevel()函数的实现如下图所示:

6、main函数

创建一个变量名为w的MainWindow类,让它显示,即执行w.show()代码,便可运行。

结果

  1. 刚打开时的俄罗斯方块游戏的开始界面:
  2. 按Space键,游戏开始,下图为正在运行的游戏界面:
  3. 按Space键,暂停时的游戏界面:(标题会变为PAUSE!)
  4. 再次按Space键,游戏继续:(标题又变为tetris)
  5. 旋转:
  6. 左右移动:
  7. 结束时的游戏界面:

分析

遇到的问题

  • 问题1:不了解如何使用Qt进行C++的编程。
    解决方法:上网查找相关书籍以及文献,例如《C++ GUI Qt4 编程》、《Qt5开发及实例》等。通过阅读书籍之后,先写一些简单的程序,等熟练掌握之后,再进行俄罗斯方块的编程。
  • 问题2:不知道如何去构建哪些类,以及类与类之间应该通过哪些方式来建立联系。
    解决方法:先去画思维程序模块结构图以及核心算法的流程图,再通过结构图和流程图明确任务该如何实现,需要哪些函数以及这些函数应该做什么。
  • 问题3:程序运行时出现程序异常结束。
    解决方法:当程序编译通过并且没有报错,然而程序却没有运行起来,这个时候的错误大多属于链接库文件错误。我一般采取以下措施:(1)debug模式下使用了release版本的库或者release模式下使用了debug版本的库;(2)在pro文件中对lib库的路径指明错误,即使用到了一些除了Qt以外的其他库,但是编译程序的时候程序找不到那个库。

心得体会

通过本次大作业俄罗斯方块游戏的开发,我从一个对C++编程懵懂的学生到现在可以熟练使用C++来进行简单程序的设计与编写。
       首先,这次大作业,使我对C++面向对象的编程有了深一步的了解,实验过程中,我遇到了许多的困难,特别是因为大多数的同学还不太适应面向对象的编程风格和思想,看待问题时总是想到用什么结构来实现该功能,而没有将问题看成一个封装的整体来考虑,所以在这次课程设计中我接触、体验了面向对象设计,使得思维在向面过程向面向对象过渡。
       其次,它培养了我的耐心。在屡次编译错误的debug过程中,焦躁的我甚至会产生“明朝散发弄扁舟”的想法,然而,当务发现程序出现的问题并加以改正后,我感觉到自己精神得到了升华,有种“挟飞仙以遨游”的舒畅感。而当最终程序运行成功,终稿敲定之时,我感觉自己的耐心与付出获得了回报。
       最后,它让我对将来的工作有了一定的了解。通过本次大作业俄罗斯方块游戏的开发,我对以后工作有了一定的了解,大概清楚了C++工程开发师的大概工作。同时,也让我熟练掌握了Qt这个重要的平台,对以后工作也有一定的帮助。
这次的课程设计,使我在今后的工作和学习中,都有了很到的启发。我想,这对于我都是个很好的经验。在这次课程设计实验中,我学到的所有东西都将让我们获益良多,不管是对于以后的学习还是工作、生活。

英文文献

  • C++ Primer, fifth edition, written by Stanley B.Lippman, Josée LaJoie, Barbara E. Moo.
  • Qt Assistant 5.9.8(MinGW 5.3.0 32-bit)(a Qt software)
  • www.cplusplus.com
  • C++ Primer Plus, sixth edition, written by Stephen Prata
  • https://getbootstrap.com/docs/5.0

对软件维护的认识

软件维护是指在软件产品发布后,因修正错误、提升性能或其他属性而进行的软件修改。软件维护类型总起来可分为四种——改正性维护、适应性维护、完善性维护和预防性维护。
       C++将数据封装成类,包含公有成员、私有成员和保护成员,其中私有成员和保护成员不能随意被外界所修改,防止不必要的错误;C++还有继承依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易,这样做,也达到了重用代码功能和提高执行效率的效果;以及多态,字面意思就是多种形态。当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。C++多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。正是继承、封装和多态,让C++在软件维护上更有其独特的魅力。

源代码

1、Block类

block.h

#ifndef BLOCK_H
#define BLOCK_H#include <QColor>class Block{public:Block();void create();void clear();void setCenterX(int x);void setCenterY(int y);void setX(int i, int x);void setY(int i, int y);void setId(int id);void setColor(QColor color);int getCenterX();int getCenterY();int getX(int i);int getY(int i);int getId();QColor getColor();private:int centerX;int centerY;int x[4];int y[4];int id;QColor color;
};#endif // BLOCK_H

block.cpp

#include "block.h"Block::Block(){memset(x, -1, sizeof (x));memset(y, -1, sizeof (y));centerX = -1;centerY = -1;id = 0;color.setRgb(255, 255, 255);
}void Block::create(){centerX = 4;int ID = rand() % 7;if (ID == 0){//··//··x[0] = centerX;y[0] = -2;x[1] = centerX;y[1] = -1;x[2] = centerX + 1;y[2] = -2;x[3] = centerX + 1;y[3] = -1;centerX = 0;centerY = 0;id = 0;color.setRgb(255, 255, 0);}else if (ID == 1){//····x[0] = centerX - 1;y[0] = -1;x[1] = centerX;y[1] = -1;x[2] = centerX + 1;y[2] = -1;x[3] = centerX + 2;y[3] = -1;centerY = -1;id = 1;color.setRgb(0, 255, 255);}else if (ID == 2){//··// ··x[0] = centerX - 1;y[0] = -2;x[1] = centerX;y[1] = -2;x[2] = centerX;y[2] = -1;x[3] = centerX + 1;y[3] = -1;centerY = -2;id = 2;color.setRgb(255, 0, 0);}else if (ID == 3){// ··//··x[0] = centerX;y[0] = -2;x[1] = centerX + 1;y[1] = -2;x[2] = centerX - 1;y[2] = -1;x[3] = centerX;y[3] = -1;centerY = -2;id = 3;color.setRgb(144, 238, 144);}else if (ID == 4){//·//···x[0] = centerX - 1;y[0] = -2;x[1] = centerX - 1;y[1] = -1;x[2] = centerX;y[2] = -1;x[3] = centerX + 1;y[3] = -1;centerY = -1;id = 4;color.setRgb(0, 0, 255);}else if (ID == 5){//  ·//···x[0] = centerX + 1;y[0] = -2;x[1] = centerX - 1;y[1] = -1;x[2] = centerX;y[2] = -1;x[3] = centerX + 1;y[3] = -1;centerY = -1;id = 5;color.setRgb(255, 165, 0);}else if (ID == 6){// ·//···x[0] = centerX;y[0] = -2;x[1] = centerX - 1;y[1] = -1;x[2] = centerX;y[2] = -1;x[3] = centerX + 1;y[3] = -1;centerY = -1;id = 6;color.setRgb(255, 0, 255);}
}void Block::clear(){memset(x, -1, sizeof (x));memset(y, -1, sizeof (y));centerX = -1;centerY = -1;id = 0;color.setRgb(255, 255, 255);
}void Block::setCenterX(int x){centerX = x;
}void Block::setCenterY(int y){centerY = y;
}void Block::setX(int i, int x){this->x[i] = x;
}void Block::setY(int i, int y){this->y[i] = y;
}void Block::setId(int id){this->id = id;
}void Block::setColor(QColor color){this->color = color;
}int Block::getCenterX(){return centerX;
}int Block::getCenterY(){return centerY;
}int Block::getX(int i){return x[i];
}int Block::getY(int i){return y[i];
}int Block::getId(){return id;
}QColor Block::getColor(){return color;
}

2、Tetris类

tetris.h

#ifndef TETRIS_H
#define TETRIS_H#include <time.h>
#include <stdlib.h>
#include "block.h"class Tetris{public:Tetris();void init();void createBlock();void createNextBlock();void createShadowBlock();bool move(int dx, int dy);bool moveLeft();bool moveRight();bool moveDown();bool rotate();bool gameOver();int getLine();void killLines();int getScore();int getLevel();Block getBlock();Block getNextBlock();Block getShadowBlock();bool getBox(int x, int y);private:int score;int level;Block block;Block nextBlock;Block shadowBlock;bool box[10][20];
};#endif // TETRIS_H

tetris.cpp

#include "tetris.h"Tetris::Tetris(){srand(unsigned(time(0)));score = 0;level = 1;memset(box, 0, sizeof (box));block.clear();createNextBlock();
}void Tetris::init(){srand(unsigned(time(0)));score = 0;level = 1;memset(box, 0, sizeof (box));block.clear();createNextBlock();
}void Tetris::createBlock(){block = nextBlock;createNextBlock();
}void Tetris::createNextBlock(){nextBlock.create();
}void Tetris::createShadowBlock(){shadowBlock = block;bool flag = true;while (flag){for (int i = 0; i < 4; i++){if (box[shadowBlock.getX(i)][shadowBlock.getY(i)+1]){flag = false;break;}}if (flag){for (int i = 0; i < 4; i++){shadowBlock.setY(i, shadowBlock.getY(i)+1);}shadowBlock.setCenterY(shadowBlock.getCenterY()+1);}for (int i = 0; i < 4; i++){if (shadowBlock.getY(i) == 19){flag = false;break;}}}
}bool Tetris::move(int dx, int dy){int tempX[4], tempY[4];int tempCenterX, tempCenterY;for (int i = 0; i < 4; i++){tempX[i] = block.getX(i) + dx;tempY[i] = block.getY(i) + dy;if (tempX[i] < 0 || tempX[i] >= 10){return false;}if (tempY[i] >=0 && tempY[i] < 20){if (box[tempX[i]][tempY[i]]){return false;}}else if (tempY[i] >= 20){return false;}}tempCenterX = block.getCenterX() + dx;tempCenterY = block.getCenterY() + dy;for (int i = 0; i < 4; i++){block.setX(i, tempX[i]);block.setY(i, tempY[i]);}block.setCenterX(tempCenterX);block.setCenterY(tempCenterY);createShadowBlock();return true;
}bool Tetris::moveLeft(){if (move(-1, 0)){return true;}else{return false;}
}bool Tetris::moveRight(){if (move(1, 0)){return true;}else{return false;}
}bool Tetris::moveDown(){if (! move(0, 1)){for (int i = 0; i < 4; i++){int x = block.getX(i);int y = block.getY(i);if (y >= 0){box[x][y] = 1;}}killLines();if (gameOver()){return false;}else{createBlock();}}return true;
}bool Tetris::rotate(){int tempX[4], tempY[4];int tempCenterX, tempCenterY;if (block.getId() == 0){return false;}for (int i = 0; i < 4; i++){tempX[i] = block.getCenterX() + block.getCenterY() - block.getY(i);tempY[i] = block.getCenterY() - block.getCenterX() + block.getX(i);if (tempX[i] < 0 || tempX[i] >= 10){return false;}if (tempY[i] >=0 && tempY[i] < 20){if (box[tempX[i]][tempY[i]]){return false;}}else if (tempY[i] >= 20){return false;}}tempCenterX = block.getCenterX();tempCenterY = block.getCenterY();for (int i = 0; i < 4; i++){block.setX(i, tempX[i]);block.setY(i, tempY[i]);}block.setCenterX(tempCenterX);block.setCenterY(tempCenterY);createShadowBlock();return true;
}bool Tetris::gameOver(){for (int i = 0; i < 10; i++){if (box[i][0]){return true;}}return false;
}int Tetris::getLine(){for (int j = 0; j < 20; j++){bool flag = true;for (int i = 0; i < 10; i++){if (! box[i][j]){flag = false;break;}}if (flag){return j;}}return -1;
}void Tetris::killLines(){int cnt = 0;int line = getLine();while (line != -1){for (int j = line; j >0; j--){for (int i = 0; i < 10; i++){box[i][j] = box[i][j-1];}}cnt++;line = getLine();}score += cnt * cnt;level = score/10 + 1;
}int Tetris::getScore(){return score;
}int Tetris::getLevel(){return level;
}Block Tetris::getBlock(){return block;
}Block Tetris::getNextBlock(){return nextBlock;
}Block Tetris::getShadowBlock(){return shadowBlock;
}bool Tetris::getBox(int x, int y){return box[x][y];
}

3、Box类

box.h

#ifndef BOX_H
#define BOX_H#include <QWidget>
#include <QPainter>
#include "tetris.h"class Box: public QWidget{Q_OBJECTpublic:explicit Box(QWidget *parent = nullptr);void updateTetris(Tetris tetris);void paintEvent(QPaintEvent *event);private:Block block;Block shadowBlock;bool box[10][20];
};#endif // BOX_H

box.cpp

#include "box.h"Box::Box(QWidget *parent) : QWidget(parent){block.clear();shadowBlock.clear();memset(box, 0, sizeof (box));int w = 30*10 + 4*(10-1);int h = 30*20 + 4*(20-1);setFixedSize(w, h);
}void Box::updateTetris(Tetris tetris){block = tetris.getBlock();shadowBlock = tetris.getShadowBlock();for (int i = 0; i < 10; i++){for (int j = 0; j < 20; j++){box[i][j] = tetris.getBox(i, j);}}repaint();
}void Box::paintEvent(QPaintEvent *event){QPainter painter(this);painter.setPen(Qt::black);painter.drawRect(this->rect().x(),this->rect().y(),this->rect().width()-1,this->rect().height()-1);painter.setPen(Qt::white);int w = 30*10 + 4*(10-1);int h = 30*20 + 4*(20-1);setPalette(QPalette(Qt::black));setAutoFillBackground(true);for (int i = 1; i < 10; i++){painter.drawLine(i*34-2, 0, i*34-2, h);}for (int i = 1; i < 20; i++){painter.drawLine(0, i*34-2, w, i*34-2);}QPen boxPen;QBrush boxBrush;boxPen.setStyle(Qt::SolidLine);boxPen.setColor(Qt::gray);boxBrush.setStyle(Qt::SolidPattern);boxBrush.setColor(Qt::white);painter.setPen(boxPen);painter.setBrush(boxBrush);for (int i = 0; i < 10; i++){for (int j = 0; j < 20; j++){if (box[i][j]){painter.drawRect(i*34, j*34, 30, 30);}}}QPen blockPen;QBrush blockBrush;blockPen.setStyle(Qt::SolidLine);blockPen.setColor(Qt::gray);blockBrush.setStyle(Qt::SolidPattern);blockBrush.setColor(block.getColor());painter.setPen(blockPen);painter.setBrush(blockBrush);for (int i = 0; i < 4; i++){int x = block.getX(i);int y = block.getY(i);painter.drawRect(x*34, y*34, 30, 30);}QPen shadowBlockPen;QBrush shadowBlockBrush;shadowBlockPen.setStyle(Qt::SolidLine);shadowBlockPen.setColor(Qt::gray);shadowBlockBrush.setStyle(Qt::SolidPattern);shadowBlockBrush.setColor(QColor(shadowBlock.getColor().red(), shadowBlock.getColor().green(), shadowBlock.getColor().blue(), 150));painter.setPen(shadowBlockPen);painter.setBrush(shadowBlockBrush);for (int i = 0; i < 4; i++){int x = shadowBlock.getX(i);int y = shadowBlock.getY(i);painter.drawRect(x*34, y*34, 30, 30);}
}

4、NextBox类

nextbox.h

#ifndef NEXTBOX_H
#define NEXTBOX_H#include <QWidget>
#include <QPainter>
#include "tetris.h"class NextBox: public QWidget{Q_OBJECTpublic:explicit NextBox(QWidget *parent = nullptr);void updateNextTetris(Tetris tetris);void paintEvent(QPaintEvent *event);private:Block nextBlock;
};#endif // NEXTBOX_H

nextbox.cpp

#include "nextbox.h"NextBox::NextBox(QWidget *parent) : QWidget(parent){nextBlock.clear();int w = 30*4 + 4*(4-1);int h = 30*4 + 4*(4-1);setFixedSize(w, h);
}void NextBox::updateNextTetris(Tetris tetris){nextBlock = tetris.getNextBlock();for (int i = 0; i < 4; i++){nextBlock.setX(i, nextBlock.getX(i)-3);nextBlock.setY(i, nextBlock.getY(i)+3);}repaint();
}void NextBox::paintEvent(QPaintEvent *event){QPainter painter(this);painter.setPen(Qt::black);painter.drawRect(this->rect().x(),this->rect().y(),this->rect().width()-1,this->rect().height()-1);painter.setPen(Qt::white);int w = 30*4 + 4*(4-1);int h = 30*4 + 4*(4-1);setPalette(QPalette(Qt::black));setAutoFillBackground(true);for (int i = 1; i < 4; i++){painter.drawLine(i*34-2, 0, i*34-2, h);}for (int i = 1; i < 4; i++){painter.drawLine(0, i*34-2, w, i*34-2);}QPen nextBlockPen;QBrush nextBlockBrush;nextBlockPen.setStyle(Qt::SolidLine);nextBlockPen.setColor(Qt::gray);nextBlockBrush.setStyle(Qt::SolidPattern);nextBlockBrush.setColor(nextBlock.getColor());painter.setPen(nextBlockPen);painter.setBrush(nextBlockBrush);for (int i = 0; i < 4; i++){int x = nextBlock.getX(i);int y = nextBlock.getY(i);painter.drawRect(x*34, y*34, 30, 30);}
}

5、MainWindow类

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QTimer>
#include <QKeyEvent>
#include <QLabel>
#include <QMessageBox>
#include "box.h"
#include "nextbox.h"const int STATUS_ON = 0;//游戏进行
const int STATUS_PAUSE = 1;//游戏暂停
const int STATUS_OFF = 2;//游戏未开始
const int STATUS_END = 3;//游戏结束class MainWindow: public QMainWindow{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();void keyPressEvent(QKeyEvent *event);void updateScore();void updateLevel();public slots:void onTimer();private:int status;QTimer *timer;Tetris tetris;Box *box;NextBox *nextBox;QLabel *nextLabel;QLabel *scoreTitleLabel;QLabel *scoreLabel;QLabel *levelTitleLabel;QLabel *levelLabel;QLabel *controlLabel;QLabel *upLabel;QLabel *downLabel;QLabel *leftLabel;QLabel *rightLabel;QLabel *spaceLabel;QLabel *escLabel;QLabel *renewLabel;
};#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent){this->resize(750, 780);box = new Box;box->setParent(this);box->setGeometry(20, 40, 350, 700);nextBox = new NextBox;nextBox->setParent(this);nextBox->setGeometry(480, 90, 150, 150);nextLabel = new QLabel(tr("下一个:"));nextLabel->setParent(this);nextLabel->setGeometry(500, 40, 150, 50);QFont font("黑体", 20, 100);scoreTitleLabel = new QLabel(tr("得分:"));scoreTitleLabel->setParent(this);scoreTitleLabel->setGeometry(440, 260, 150, 50);scoreTitleLabel->setFont(font);scoreLabel = new QLabel(tr("0"));scoreLabel->setParent(this);scoreLabel->setGeometry(600, 260, 150, 50);scoreLabel->setFont(font);levelTitleLabel = new QLabel(tr("等级:"));levelTitleLabel->setParent(this);levelTitleLabel->setGeometry(440, 330, 150, 50);levelTitleLabel->setFont(font);levelLabel = new QLabel(tr("1"));levelLabel->setParent(this);levelLabel->setGeometry(600, 330, 150, 50);levelLabel->setFont(font);controlLabel = new QLabel(tr("按键提示:"));controlLabel->setParent(this);controlLabel->setGeometry(490, 420, 200, 50);upLabel = new QLabel(tr("Up-旋转"));upLabel->setParent(this);upLabel->setGeometry(380, 470, 200, 50);downLabel = new QLabel(tr("Down-向下加速"));downLabel->setParent(this);downLabel->setGeometry(570, 470, 200, 50);leftLabel = new QLabel(tr("Left-向左移动"));leftLabel->setParent(this);leftLabel->setGeometry(380, 520, 200, 50);rightLabel = new QLabel(tr("Right-向右移动"));rightLabel->setParent(this);rightLabel->setGeometry(570, 520, 200, 50);spaceLabel = new QLabel(tr("Space-开始/暂停"));spaceLabel->setParent(this);spaceLabel->setGeometry(460, 570, 200, 50);escLabel = new QLabel(tr("Esc-退出游戏"));escLabel->setParent(this);escLabel->setGeometry(380, 620, 200, 50);renewLabel = new QLabel(tr("F5-重新开始"));renewLabel->setParent(this);renewLabel->setGeometry(570, 620, 200, 50);status = STATUS_OFF;nextBox->updateNextTetris(tetris);timer = new QTimer(this);connect(timer, SIGNAL(timeout()), this, SLOT(onTimer()));
}MainWindow::~MainWindow(){}void MainWindow::keyPressEvent(QKeyEvent *event){if (event->key() == Qt::Key_Left){if (tetris.moveLeft() && status == STATUS_ON){box->updateTetris(tetris);}}else if (event->key() == Qt::Key_Right){if (tetris.moveRight() && status == STATUS_ON){box->updateTetris(tetris);}}else if (event->key() == Qt::Key_Up){if (tetris.rotate() && status == STATUS_ON){box->updateTetris(tetris);}}else if (event->key() == Qt::Key_Down){if (status == STATUS_ON){if (tetris.moveDown()){box->updateTetris(tetris);nextBox->updateNextTetris(tetris);updateScore();updateLevel();}else{timer->stop();QString s;int score = tetris.getScore();int level = score/10 + 1;s += "Well Done!\n";s += QString("Your Score is: %1\n").arg(score);s += QString("Your level is: %1!").arg(level);QMessageBox::information(this, tr("Game Over"), s);status = STATUS_END;}}}else if (event->key() == Qt::Key_Space){if (status == STATUS_PAUSE){int level = tetris.getLevel();if (level < 9){timer->start(1100 - level*100);}else{timer->start(200);}status = STATUS_ON;setWindowTitle(tr("tetris"));}else if (status == STATUS_OFF){tetris.createBlock();box->updateTetris(tetris);nextBox->updateNextTetris(tetris);updateScore();updateLevel();int level = tetris.getLevel();if (level < 9){timer->start(1100 - level*100);}else{timer->start(200);}status = STATUS_ON;}else if (status == STATUS_END){tetris.init();tetris.createBlock();box->updateTetris(tetris);nextBox->updateNextTetris(tetris);updateScore();int level = tetris.getScore()/10 + 1;if (level < 9){timer->start(1100 - level*100);}else{timer->start(200);}status = STATUS_ON;}else if (status == STATUS_ON){timer->stop();status = STATUS_PAUSE;setWindowTitle(tr("PAUSE!"));}}else if (event->key() == Qt::Key_F5){timer->stop();tetris.init();box->updateTetris(tetris);nextBox->updateNextTetris(tetris);updateScore();updateLevel();status = STATUS_OFF;}else if (event->key() == Qt::Key_Escape){close();}}void MainWindow::onTimer(){if(tetris.moveDown()){box->updateTetris(tetris);nextBox->updateNextTetris(tetris);updateScore();updateLevel();}else{timer->stop();QString s;int score = tetris.getScore();int level = tetris.getLevel();s += "Well Done!\n";s += QString("Your Score is: %1\n").arg(score);s += QString("Your level is: %1!").arg(level);QMessageBox::information(this, tr("Game Over"), s);status = STATUS_END;}
}void MainWindow::updateScore(){QString s;int score = tetris.getScore();s += QString("%1").arg(score);scoreLabel->setText(s);
}void MainWindow::updateLevel(){QString s;int level = tetris.getLevel();s += QString("%1").arg(level);levelLabel->setText(s);if (level < 9){timer->start(1100 - level*100);}else{timer->start(200);}
}

6、main函数

main.cpp

#include "mainwindow.h"
#include <QApplication>int main(int argc, char *argv[]){QApplication a(argc, argv);MainWindow w;w.show();return a.exec();
}

欢迎大佬莅临指导。

小游戏:俄罗斯方块(Qt 5.9.8)相关推荐

  1. 鸿蒙小游戏-俄罗斯方块

    作者:225王宗振 前言 为了更好地熟练掌握鸿蒙手机应用开发,查阅资料和算法尝试开发鸿蒙小游戏--俄罗斯方块. 概述 完成鸿蒙小游戏APP在手机上的编译在项目中所使用到的软件为DevEco Studi ...

  2. 原生js小游戏——俄罗斯方块

    还记得童年时期的小游戏俄罗斯方块吗?我发现用js就可以写出来 页面效果如下: 具体代码如下: 首先展示css样式: .c {margin: 1px;width: 19px;height: 19px;b ...

  3. python tkinter火柴人_用Python实现童年小游戏俄罗斯方块!别说还挺好玩!

    原标题:用Python实现童年小游戏俄罗斯方块!别说还挺好玩! 前言 大三上学期的程序设计实训大作业,挑了其中一个我认为最简单的的<图书管理系统>来写.用python写是因为py有自带的G ...

  4. python实现小游戏论文_用Python实现童年小游戏俄罗斯方块

    在那个电子产品比较匮乏的年代,小游戏机 还是为数不多的游戏类电子产品,对小孩子更是有着不可抗拒的魔力,在当时如果哪个小孩买了一个小游戏机,大伙一定迅速围上去... 俄罗斯方块作为其中一款小游戏,尽管规 ...

  5. 【Python教你一招】用Python实现童年小游戏俄罗斯方块

    学习素材与源码在Python学习交流群:733089476 获取 在那个电子产品比较匮乏的年代,小游戏机还是为数不多的游戏类电子产品,对小孩子更是有着不可抗拒的魔力,在当时如果哪个小孩买了一个小游戏机 ...

  6. Java小游戏-俄罗斯方块

    摘 要 随着时代的不断发展,个人电脑也在不断普及,一些有趣的桌面游戏已经成为人们在使用计算机进行工作或工作之余休闲娱乐的首选,从最开始的Windows系统自带的黑白棋.纸牌.扫雷等游戏开始,到现在目不 ...

  7. Eclipse小游戏-俄罗斯方块

    个人写的Eclipse小游戏,大家代码写累了,可以拿来玩玩. 分为两个部分,一个是eclipse插件,直接将jar包放到eclipse的drops目录下,重启eclipse就可生效:另外还弄了个Ser ...

  8. Python小游戏(俄罗斯方块)

    玩法:童年经典,普通模式没啥意思,小时候我们都是玩加速的. 源码分享: import os import sys import random from modules import * from Py ...

  9. Pascal小游戏 俄罗斯方块怀旧版

    俄罗斯方块怀旧版(注释版) {$APPTYPE GUI} {$MODE DELPHI} program WinPiece; uses Windows; const AppName = 'WinPiec ...

  10. python小游戏——俄罗斯方块

    最近研究pygame游戏制作板块,本次对于简单的俄罗斯方块进行介绍. 1.首先引入我们需要用到的pygame库和random库(pygame库基础知识请移步首页) import pygame impo ...

最新文章

  1. 知不知道 Thread.sleep(0) 到底有什么用?
  2. linux 双mysql_MySQL双主互备+Keepalived高可用架构实现案例
  3. java model 封装_Java封装统一的Result Model案例
  4. 笨方法python3_“笨方法”学Python3,习题 43 。
  5. php httputils,Android 自定义网络加载工具类 HttpURLConnectionUtils
  6. 知乎7万赞回答:你思考问题的方式,决定了你的层次
  7. Visio2019中插入数学公式
  8. 青龙面板 抖音极速版
  9. 迅雷 linux 命令行 版本号,linux下完美运行迅雷5.8.9.662
  10. 计算机培训校本研修心得,关于校本研修培训心得体会(精选10篇)
  11. WEB入门.九 导航菜单
  12. hadoop集群搭建(系统Debian,ssh工具MobaXterm)
  13. 用html画动漫人物,画动漫人物的步骤?
  14. 用rest造句子_rest造句
  15. Android解决Can't create handler inside thread that has not called Looper.prepare()
  16. Solidity节省GAS的方法
  17. 职场上被人针对要不要告诉领导
  18. 如何批量调整多个视频文件的尺寸大小
  19. linux5.8关闭屏幕保护,chia linux
  20. PbootCMS采集-PbootCMS采集插件-免费PbootCMS采集方法点解

热门文章

  1. 转:动态规划题目分类
  2. Java_控制流程(if、switch、while、for、continue、break、结束外部循环)
  3. 微型计算机用的是直流电吗,皮卡丘用的是直流电还是交流电?⚡️⚡️
  4. Android 如何访问网络
  5. 艾司博讯:拼多多拼单不想要了怎么退
  6. SuSe软件安装命令
  7. javascript实现图片滚动效果
  8. 利用word的freemarker模板导出word文件
  9. 言语理解-片段阅读的结构剖析练习
  10. SAT阅读模拟练习题一篇