IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> 小游戏:俄罗斯方块(Qt 5.9.8) -> 正文阅读

[游戏开发]小游戏:俄罗斯方块(Qt 5.9.8)

游戏介绍

???????小游戏所使用的语言为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()函数实现如下图所示:
    Block的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()函数的实现如下图所示:
    Tetris的init()函数
  • createBlock()函数的实现如下图所示:
    Tetris的createBlock()函数
  • createShadowBlock()函数的实现如下图所示:
    Tetris的createShadowBlock()函数
  • move(int dx, int dy)函数的实现如下图所示:
    Tetris的move(int dx, int dy)函数
  • moveDown()函数的实现如下图所示:
    Tetris的moveDown()函数
  • rotate()函数的实现如下图所示:
    Tetris的rotate()函数
  • gameOver()函数的实现如下图所示:
    Tetris的gameOver()函数
  • getLine()函数的实现如下图所示:
    Tetris的getLine()函数
  • killLines()函数的实现如下图所示:
    Tetris的killLines()函数

3、Box类

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

  • updateTetris(Tetris tetris)函数的实现如下图所示:
    Box的updateTetris(Tetris tetris)函数
  • paintEvent(QPaintEvent *event)函数的实现如下图所示:
    在这里插入图片描述

4、NextBox类

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

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

5、MainWindow类

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

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

6、main函数

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

结果

  1. 刚打开时的俄罗斯方块游戏的开始界面:
    刚打开时的俄罗斯方块游戏的开始界面
  2. 按Space键,游戏开始,下图为正在运行的游戏界面:
    按Space键,游戏开始,下图为正在运行的游戏界面
  3. 按Space键,暂停时的游戏界面:(标题会变为PAUSE!)
    按Space键,暂停时的游戏界面
  4. 再次按Space键,游戏继续:(标题又变为tetris)
    再次按Space键,游戏继续
  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_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_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_OBJECT

    public:
        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_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_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();
}

欢迎大佬莅临指导。

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2021-09-03 12:16:13  更:2021-09-03 12:17:26 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年9日历 -2024/9/21 11:27:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码