游戏介绍
???????小游戏所使用的语言为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()代码,便可运行。
结果
- 刚打开时的俄罗斯方块游戏的开始界面:
- 按Space键,游戏开始,下图为正在运行的游戏界面:
- 按Space键,暂停时的游戏界面:(标题会变为PAUSE!)
- 再次按Space键,游戏继续:(标题又变为tetris)
- 旋转:
- 左右移动:
- 结束时的游戏界面:
分析
遇到的问题
- 问题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.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.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_OBJECT
public:
explicit Box(QWidget *parent = nullptr);
void updateTetris(Tetris tetris);
void paintEvent(QPaintEvent *event);
private:
Block block;
Block shadowBlock;
bool box[10][20];
};
#endif
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_OBJECT
public:
explicit NextBox(QWidget *parent = nullptr);
void updateNextTetris(Tetris tetris);
void paintEvent(QPaintEvent *event);
private:
Block nextBlock;
};
#endif
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_OBJECT
public:
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.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();
}
欢迎大佬莅临指导。
|