Qt实现俄罗斯方块

本文实例为大家分享了Qt实现俄罗斯方块,供大家参考,具体内容如下

最近在学习Qt,用它来进行图形界面的开发还是很方便的,想着做一个小游戏来锻炼一下自己,就想到了小时候玩的俄罗斯方块。折腾了一段时间,虽然界面做的不美观,但是总算是实现了基本的功能。

首先我写了一个俄罗斯方块的类Tetris,通过这个类来进行这个游戏的数据的处理;然后游戏窗口是继承的QWidget类,用来显示游戏的方块;“下一个方块”窗口也是继承的QWidget类,用来显示下一个方块;控制提示和分数的显示用的QLabel。然后将将这些控件整合到继承自QMainWindow的mainWindow类。运行的结果如下:

Tetris类:一共有7中不同形状的方块(如下图),每个方块由四个方格组成,Block结构体用来存储方块的方格坐、中心方格坐标、ID等数据,移动中的方块和下移个方块都是通过这个结构体来操作的;已经落下的方块的方格存储在二维数组box[][]中,x坐标从左到右为正方向,y坐标从上到下为正方向(如下图)。

项目源文件

  • tetris.h
  • tetris.cpp
  • tetrisbox.h
  • tetrisbox.cpp
  • nexttetris.h
  • nexttetris.cpp
  • mainwindow.h
  • mainwindow.cpp

tetris.h

#ifndef TETRIS_H
#define TETRIS_H

//为了获得随机数
#include <cstdlib>
#include <ctime>

#define MAXX 10     //显示窗口的横向格数
#define MAXY 20     //显示窗口的竖向格数
#define NEXTMAXX 6  //“下一个”显示窗口的横向格数
#define NEXTMAXY 6  //“下一个”显示窗口的竖向格数
#define WIDTH 30    //单格的宽度
#define HEIGHT 30   //单格的高度
#define INTERVAL 4  //单格之间的间隔
#define COUNT 4     //每个方块的格数

//Block结构体:一个方块
struct Block
{
    int x[COUNT];   //方块单格的x坐标
    int y[COUNT];   //方块单格的y坐标
    int centerX;    //方块的中心x坐标
    int centerY;    //方块的中心y坐标
    int ID;         //方块的ID
};

class Tetris
{
public:
    Tetris();
    void createBlock();             //创建当前方块
    Block getNextBlock();           //获得下一个方块
    Block getBlock();               //获得当前方块
    int getScore();                 //获得分数
    int getBox(int x, int y);       //获得相应坐标的状态
    bool rotate();                  //旋转
    bool moveToLeft();              //向左移动
    bool moveToRight();             //向右移动
    bool moveToBottom();            //向下移动
    bool isEnd();                   //判断是否结束
    void killLines();               //消去整行
    void clear();                   //重新初始化

    static int getWidth();          //获得窗口的宽度
    static int getHeight();         //获得窗口的高度
    static int getNextWidth();      //获得“下一个”窗口的宽度
    static int getNextHeight();     //获得“下一个”窗口的高度

private:
    void createNextBlock();         //创建下一个方块
    bool move(int dx, int dy);      //是否可以移动
    void blockToBox();              //将block中的数据转移到box中
    bool isRotatable();             //是否可以旋转
    int getFirstFullLine();         //获得第一个整行

private:
    int score;          //分数
    Block block;        //当前方块
    Block nextBlock;    //下一个方块
    int box[MAXX][MAXY];//方格的坐标系 1表示右方格,0表示没有方格

};

#endif // TETRIS_H

Tetris.cpp

#include "tetris.h"

Tetris::Tetris()
{
    //初始化随机数发生器
    srand(unsigned(time(NULL)));

    //初始化成员变量
    score = 0;
    for (int i = 0; i < MAXX; i++)
    {
        for (int j = 0; j < MAXY; j++)
        {
            box[i][j] = 0;
        }
    }
    for (int i = 0; i < COUNT; i++)
    {
        block.x[i] = -1;
        block.y[i] = -1;
    }
    block.centerX = -1;
    block.centerY = -1;
    block.ID = 0;
    //创建下一个方块
    createNextBlock();

}

//创建当前方块
//将上一次生成的下一个方块nextBlock复制给block
//并创建下一个nextBlock
void Tetris::createBlock()
{
    //nextBlock复制给block
    for (int i = 0; i < COUNT; i++)
    {
        block.x[i] = nextBlock.x[i];
        block.y[i] = nextBlock.y[i];
    }
    block.centerX = nextBlock.centerX;
    block.centerY = nextBlock.centerY;
    block.ID = nextBlock.ID;

    //创建下一个nextblock
    createNextBlock();
}

//返回下一个方块
Block Tetris::getNextBlock()
{
    return nextBlock;
}

//返回当前方块
Block Tetris::getBlock()
{
    return block;
}

//返回当前分数
int Tetris::getScore()
{
    return score;
}

//返回坐标(x,y)的值,以判断是否右方格
int Tetris::getBox(int x, int y)
{
    return box[x][y];
}

//旋转当前方块
//旋转成功返回true,否则返回false
bool Tetris::rotate()
{
    if (isRotatable())
    {
        return true;
    }
    else
    {
        return false;
    }
}

//将当前方块向左移动一格
//成功返回true,否则返回false
bool Tetris::moveToLeft()
{
    if (move(-1, 0))
    {
        return true;
    }
    else
    {
        return false;
    }
}

//将当前方块向右移动一格
//成功返回true,否则返回false
bool Tetris::moveToRight()
{
    if (move(1, 0))
    {
        return true;
    }
    else
    {
        return false;
    }
}

//将方块向下移动一格
//成功返回true, 游戏结束返回false
bool Tetris::moveToBottom()
{
    if (!move(0, 1))
    {
        //移动不成功

        blockToBox();   //将当前方块复制到box中
        killLines();    //消行

        //判断是否结束
        //否则创建新的方块
        if(isEnd())
        {
            return false;
        }
        else
        {
            createBlock();
        }
    }
    return true;
}

//判断游戏是否结束
//结束条件为第一行有方格
bool Tetris::isEnd()
{
    int j = 0;
    for (int i = 0; i < MAXX; i++)
    {
        if (box[i][j] == 1)
        {
            return true;
        }
    }
    return false;
}

//消掉整行并进行分数奖励
void Tetris::killLines()
{
    int count = 0;  //一次消掉的行数
    //通过getFirstFullLine()函数获得从上到下第一个整行
    //并将其上的行向下平移一行,达到消行的效果
    int temp = 0;
    while ((temp = getFirstFullLine()) != -1)
    {
        for (int j = temp; j >0; j--)
        {
            for (int i = 0; i < MAXX; i++)
            {
                box[i][j] = box[i][j-1];
            }
        }
        count++;
    }
    //消行的分数奖励
    score += count * count * 10;
}

//对成员变量进行初始化,重新开始游戏
void Tetris::clear()
{
    //初始化
    score = 0;
    srand(unsigned(time(NULL)));
    for (int i = 0; i < MAXX; i++)
    {
        for (int j = 0; j < MAXY; j++)
        {
            box[i][j] = 0;
        }
    }
    for (int i = 0; i < COUNT; i++)
    {
        block.x[i] = -1;
        block.y[i] = -1;
    }
    block.centerX = -1;
    block.centerY = -1;
    block.ID = 0;
    //创建下一个方块
    createNextBlock();
}

//获得游戏窗口的宽度
int Tetris::getWidth()
{
    return MAXX * WIDTH + (MAXX - 1) * INTERVAL;
}

//获得游戏窗口的高度
int Tetris::getHeight()
{
    return MAXY * HEIGHT + (MAXY - 1) * INTERVAL;
}

//获得“下一个”窗口的宽度
int Tetris::getNextWidth()
{
    return NEXTMAXX * WIDTH + (NEXTMAXX - 1) * INTERVAL;
}

//获得“下一个”窗口的高度
int Tetris::getNextHeight()
{
    return NEXTMAXY * WIDTH + (NEXTMAXY - 1) * INTERVAL;
}

//创建“下一个”方块
void Tetris::createNextBlock()
{
    int centerX = (MAXX - 1) / 2;   //中心x坐标
    int ID = rand() % 7;            //获得0 - 6的随机数
    //根据不同的随机数创建方块
    switch (ID)
    {
    case 0:
        //##
        //##
        nextBlock.x[0] = centerX;
        nextBlock.x[1] = centerX;
        nextBlock.x[2] = centerX + 1;
        nextBlock.x[3] = centerX + 1;
        nextBlock.y[0] = -2;
        nextBlock.y[1] = -1;
        nextBlock.y[2] = -2;
        nextBlock.y[3] = -1;
        nextBlock.centerX = 0;
        nextBlock.centerY = 0;
        nextBlock.ID = 0;
        break;
    case 1:
        //####
        //
        nextBlock.x[0] = centerX - 1;
        nextBlock.x[1] = centerX;
        nextBlock.x[2] = centerX + 1;
        nextBlock.x[3] = centerX + 2;
        nextBlock.y[0] = -1;
        nextBlock.y[1] = -1;
        nextBlock.y[2] = -1;
        nextBlock.y[3] = -1;
        nextBlock.centerX = centerX;
        nextBlock.centerY = -1;
        nextBlock.ID = 1;
        break;
    case 2:
        //##
        // ##
        nextBlock.x[0] = centerX - 1;
        nextBlock.x[1] = centerX;
        nextBlock.x[2] = centerX;
        nextBlock.x[3] = centerX + 1;
        nextBlock.y[0] = -2;
        nextBlock.y[1] = -2;
        nextBlock.y[2] = -1;
        nextBlock.y[3] = -1;
        nextBlock.centerX = centerX;
        nextBlock.centerY = -2;
        nextBlock.ID = 2;
        break;
    case 3:
        // ##
        //##
        nextBlock.x[0] = centerX;
        nextBlock.x[1] = centerX + 1;
        nextBlock.x[2] = centerX - 1;
        nextBlock.x[3] = centerX;
        nextBlock.y[0] = -2;
        nextBlock.y[1] = -2;
        nextBlock.y[2] = -1;
        nextBlock.y[3] = -1;
        nextBlock.centerX = centerX;
        nextBlock.centerY = -2;
        nextBlock.ID = 3;
        break;
    case 4:
        //#
        //###
        nextBlock.x[0] = centerX - 1;
        nextBlock.x[1] = centerX - 1;
        nextBlock.x[2] = centerX;
        nextBlock.x[3] = centerX + 1;
        nextBlock.y[0] = -2;
        nextBlock.y[1] = -1;
        nextBlock.y[2] = -1;
        nextBlock.y[3] = -1;
        nextBlock.centerX = centerX;
        nextBlock.centerY = -1;
        nextBlock.ID = 4;
        break;
    case 5:
        //  #
        //###
        nextBlock.x[0] = centerX + 1;
        nextBlock.x[1] = centerX - 1;
        nextBlock.x[2] = centerX;
        nextBlock.x[3] = centerX + 1;
        nextBlock.y[0] = -2;
        nextBlock.y[1] = -1;
        nextBlock.y[2] = -1;
        nextBlock.y[3] = -1;
        nextBlock.centerX = centerX;
        nextBlock.centerY = -1;
        nextBlock.ID = 5;
        break;
    case 6:
        // #
        //###
        nextBlock.x[0] = centerX;
        nextBlock.x[1] = centerX - 1;
        nextBlock.x[2] = centerX;
        nextBlock.x[3] = centerX + 1;
        nextBlock.y[0] = -2;
        nextBlock.y[1] = -1;
        nextBlock.y[2] = -1;
        nextBlock.y[3] = -1;
        nextBlock.centerX = centerX;
        nextBlock.centerY = -1;
        nextBlock.ID = 6;
        break;
    default:
        break;
    }
}

//可以移动就对block进行变换,返回true
//否则返回false
bool Tetris::move(int dx, int dy)
{
    int newX[COUNT];
    int newY[COUNT];
    int newCenterX;
    int newCenterY;
    for (int i = 0; i < COUNT; i++)
    {
        newX[i] = block.x[i] + dx;
        newY[i] = block.y[i] + dy;

        //对变换后的坐标进行判定

        //x坐标超出范围返回false
        if (newX[i] < 0 || newX[i] >= MAXX)
        {
            return false;
        }
        //y坐标在0 - MAXY之间就对box中的状态进行判定
        //box中为1则返回false
        if (newY[i] >=0 && newY[i] < MAXY)
        {
            if (box[newX[i]][newY[i]] == 1)
            {
                return false;
            }
        }//y坐标超出最大值返回false
        else if (newY[i] >= MAXY)
        {
            return false;
        }

    }
    newCenterX = block.centerX + dx;
    newCenterY = block.centerY + dy;

    //满足条件就将新的x和y坐标赋值给block
    for (int i = 0; i < COUNT; i++)
    {
        block.x[i] = newX[i];
        block.y[i] = newY[i];
    }
    block.centerX = newCenterX;
    block.centerY = newCenterY;

    return true;
}

//可以旋转就对block进行变换,返回true
//否则返回false
bool Tetris::isRotatable()
{
    int newX[COUNT];
    int newY[COUNT];
    int newCenterX;
    int newCenterY;

    if (block.ID == 0)
    {
        return false;
    }

    for (int i = 0; i < COUNT; i++)
    {
        int nx = block.x[i] - block.centerX;
        int ny = block.y[i] - block.centerY;
        newX[i] = nx * 0 + ny * (-1) + block.centerX;
        newY[i] = nx * 1 + ny * 0 + block.centerY;

        //对变换后的坐标进行判定

        //x坐标超出范围返回false
        if (newX[i] < 0 || newX[i] >= MAXX)
        {
            return false;
        }
        //y坐标在0 - MAXY 之间就对box中的状态进行判定
        //box中为1则返回false
        if (newY[i] >=0 && newY[i] < MAXY)
        {
            if (box[newX[i]][newY[i]] == 1)
            {
                return false;
            }
        }//y坐标超过最大值返回false
        else if (newY[i] >= MAXY)
        {
            return false;
        }
    }
    newCenterX = block.centerX;
    newCenterY = block.centerY;

    //满足条件后进行block的赋值
    for (int i = 0; i < COUNT; i++)
    {
        block.x[i] = newX[i];
        block.y[i] = newY[i];
    }
    block.centerX = newCenterX;
    block.centerY = newCenterY;

    return true;
}

//将block中数据复制到box中
void Tetris::blockToBox()
{
    for (int i = 0; i < COUNT; i++)
    {
        int x = block.x[i];
        int y = block.y[i];
        if (y >= 0)
        {
            box[x][y] = 1;
        }
    }
}

//获得第一个整行的行数,并返回
int Tetris::getFirstFullLine()
{
    //这里j从1开始就好
    for (int j = 0; j < MAXY; j++)
    {
        bool judgement = true;
        for (int i = 0; i < MAXX; i++)
        {
            if (box[i][j] == 0)
            {
                judgement = false;
                break;
            }
        }
        if (judgement)
        {
            return j;
        }
    }
    return -1;
}

tetrisbox.h

#ifndef TETRISBOX_H
#define TETRISBOX_H

#include <QWidget>
#include <QPaintEvent>
#include <QPainter>
#include <QPalette>
#include <QPen>
#include <QBrush>
#include <QColor>
//为了使用Block
#include "tetris.h"

class TetrisBox : public QWidget
{
    Q_OBJECT
public:
    explicit TetrisBox(QWidget *parent = nullptr);
    void updateTetris(Tetris tetris);       //更新数据和视图
    void paintEvent(QPaintEvent *event);    //绘制视图

signals:

public slots:

private:
    Block block;            //用来储存Tetris中block的数据
    int box[MAXX][MAXY];    //用来存储Tetris中box的数据
};

#endif // TETRISBOX_H

tetrisbox.cpp

#include "tetrisbox.h"

TetrisBox::TetrisBox(QWidget *parent) : QWidget(parent)
{
    //对block初始化
    for (int i = 0; i < COUNT; i++)
    {
        block.x[i] = -1;
        block.y[i] = -1;
    }
    block.centerX = -1;
    block.centerY = -1;
    block.ID = -1;
    //对box初始化
    for (int i = 0; i < MAXX; i++)
    {
        for (int j = 0; j < MAXY; j++)
        {
            box[i][j] = 0;
        }
    }

    //设置本游戏窗口的宽度和高度
    //并设置背景为黑色
    int w = Tetris::getWidth();
    int h = Tetris::getHeight();
    setFixedSize(w, h);
    setPalette(QPalette(Qt::black));
    setAutoFillBackground(true);
}

void TetrisBox::updateTetris(Tetris tetris)
{
    //更新block
    block = tetris.getBlock();
    //更新box
    for (int i = 0; i < MAXX; i++)
    {
        for (int j = 0; j < MAXY; j++)
        {
            box[i][j] = tetris.getBox(i, j);
        }
    }
    repaint();
}

void TetrisBox::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    QPen pen;
    QBrush brush;
    pen.setStyle(Qt::SolidLine);
    pen.setColor(QColor(255, 255, 255));
    brush.setStyle(Qt::SolidPattern);
    brush.setColor(QColor(255, 255, 255));
    painter.setPen(pen);
    painter.setBrush(brush);

    //绘制box中的内容
    for (int i = 0; i < MAXX; i++)
    {
        for (int j = 0; j < MAXY; j++)
        {
            if (box[i][j] == 1)
            {
                int x = i * WIDTH + i * INTERVAL;
                int y = j * HEIGHT + j * INTERVAL;
                painter.drawRect(x, y, WIDTH, HEIGHT);
            }
        }
    }
    //绘制block中的内容
    for (int i = 0; i < COUNT; i++)
    {
        int x = block.x[i];
        int y = block.y[i];
        int x1 = x * WIDTH + x * INTERVAL;
        int y1 = y * HEIGHT + y * INTERVAL;
        painter.drawRect(x1, y1, WIDTH, HEIGHT);
    }
}

nexttetrisbox.h

#ifndef NEXTTETRISBOX_H
#define NEXTTETRISBOX_H

#include <QWidget>
#include <QWidget>
#include <QPaintEvent>
#include <QPen>
#include <QBrush>
#include <QPainter>
#include <QColor>
#include "tetris.h"

#define RESTX (MAXX - NEXTMAXX) / 2     //方块x坐标的转换常数
#define RESTY 4                         //方块y坐标的转换常数

class NextTetrisBox : public QWidget
{
    Q_OBJECT
public:
    explicit NextTetrisBox(QWidget *parent = nullptr);
    void updateNextTetris(Tetris tetris);   //更新“下一个”的数据和视图
    void paintEvent(QPaintEvent *event);    //绘制视图

signals:

public slots:

private:
    Block nextBlock;    //“下一个”方块
};

#endif // NEXTTETRISBOX_H

nexttetris.cpp

#include "nexttetrisbox.h"

NextTetrisBox::NextTetrisBox(QWidget *parent) : QWidget(parent)
{

    //初始化nextBlock
    for (int i = 0; i < COUNT; i++)
    {
        nextBlock.x[i] = -1;
        nextBlock.y[i] = -1;
    }
    nextBlock.centerX = -1;
    nextBlock.centerY = -1;
    nextBlock.ID = 0;

    //设置本“下一个”窗口的宽度和高度
    //并设置背景为黑色
    int w = Tetris::getNextWidth();
    int h = Tetris::getNextHeight();
    setFixedSize(w, h);
    setPalette(QPalette(Qt::black));
    setAutoFillBackground(true);
}

void NextTetrisBox::updateNextTetris(Tetris tetris)
{
    nextBlock = tetris.getNextBlock();
    for (int i = 0; i < COUNT; i++)
    {
        nextBlock.x[i] -= RESTX;
        nextBlock.y[i] += RESTY;
    }
    //重新绘制
    repaint();
}

void NextTetrisBox::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    QPen pen;
    QBrush brush;
    pen.setStyle(Qt::SolidLine);
    pen.setColor(QColor(255, 255, 255));
    brush.setStyle(Qt::SolidPattern);
    brush.setColor(QColor(255, 255, 255));
    painter.setPen(pen);
    painter.setBrush(brush);

    //绘制nextBlock中的内容
    for (int i = 0; i < COUNT; i++)
    {
        int x = nextBlock.x[i];
        int y = nextBlock.y[i];
        int x1 = x * WIDTH + x * INTERVAL;
        int y1 = y * HEIGHT + y * INTERVAL;
        painter.drawRect(x1, y1, WIDTH, HEIGHT);
    }
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QMainWindow>
#include <QPainter>
#include <QEvent>
#include <QPaintEvent>
#include <QPen>
#include <QBrush>
#include <QColor>
#include <QKeyEvent>
#include <QTimer>
#include <QGridLayout>
#include <QLabel>
#include <QMessageBox>
#include <QDesktopWidget>
#include <QApplication>
#include "tetris.h"
#include "tetrisbox.h"
#include "nexttetrisbox.h"

//游戏的状态
#define STATUS_ON 0     //游戏正常进行
#define STATUS_PAUSE 1  //游戏暂停
#define STATUS_OFF 2    //游戏未开始
#define STATUS_END 3    //游戏结束

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();
    void keyPressEvent(QKeyEvent *event);   //响应键盘事件
    void changeEvent(QEvent *event);        //窗口最小化后暂停
    void updateScore();                     //更新分数的数据和显示

public slots:
    void onTimer();

private:
    int status;                     //游戏状态
    Tetris tetris;                  //俄罗斯方块类对象
    QTimer *timer;                  //计时器
    TetrisBox *tetrisBox;           //游戏窗口
    NextTetrisBox *nextTetrisBox;   //“下一个”窗口
    QGridLayout *mainLayout;        //mainLayout
    QLabel *nextTetrisLabel;        //“下一个”窗口的标签
    QLabel *controlLabel;           //“控制”标签
    QLabel *w_controlLabel;         //W键的标签
    QLabel *s_controlLabel;         //S键的标签
    QLabel *a_controlLabel;         //A键的标签
    QLabel *d_controlLabel;         //D键的标签
    QLabel *h_controlLabel;         //H键的标签
    QLabel *j_controlLabel;         //J键的标签
    QLabel *c_controlLabel;         //C键的标签
    QLabel *m_controlLabel;         //M键的标签
    QLabel *scoreTitleLabel;        //分数标题标签
    QLabel *scoreLabel;             //分数标签(用来显示分数)

};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    //创建对象
    tetrisBox = new TetrisBox;
    nextTetrisBox = new NextTetrisBox;
    nextTetrisLabel = new QLabel(tr("下一个:"));
    controlLabel = new QLabel(tr("控制:"));
    w_controlLabel = new QLabel(tr("W-旋转"));
    s_controlLabel = new QLabel(tr("S-向下移动"));
    a_controlLabel = new QLabel(tr("A-向左移动"));
    d_controlLabel = new QLabel(tr("D-向右移动"));
    h_controlLabel = new QLabel(tr("H-开始"));
    j_controlLabel = new QLabel(tr("J-暂停"));
    c_controlLabel = new QLabel(tr("C-重新开始"));
    m_controlLabel = new QLabel(tr("M-结束游戏"));
    scoreTitleLabel = new QLabel(tr("得分:"));
    scoreLabel = new QLabel(tr("0"));
    mainLayout = new QGridLayout;
    //设置mainLayout的水平和横向的间隔为20
    mainLayout->setHorizontalSpacing(20);
    mainLayout->setVerticalSpacing(20);
    //设置mainLayout居中
    mainLayout->setAlignment(Qt::AlignCenter);
    //添加各个widget
    mainLayout->addWidget(tetrisBox, 0, 0, 14, 1);
    mainLayout->addWidget(nextTetrisLabel, 0, 1);
    mainLayout->addWidget(nextTetrisBox, 1, 1, 1, 2);
    mainLayout->addWidget(controlLabel, 5, 1);
    mainLayout->addWidget(w_controlLabel, 6, 1);
    mainLayout->addWidget(s_controlLabel, 6, 2);
    mainLayout->addWidget(a_controlLabel, 7, 1);
    mainLayout->addWidget(d_controlLabel, 7, 2);
    mainLayout->addWidget(h_controlLabel, 8, 1);
    mainLayout->addWidget(j_controlLabel, 8, 2);
    mainLayout->addWidget(c_controlLabel, 9, 1);
    mainLayout->addWidget(m_controlLabel, 9, 2);
    mainLayout->addWidget(scoreTitleLabel, 12, 1);
    mainLayout->addWidget(scoreLabel, 12, 2);

    //因为mainWindow已有一个layout,所以不能直接将mainLayout
    //设置到mainWindow中,需要先将mainLayout设置为一个widget的layout
    //在将widget设置为mainLayout的centralWidget
    QWidget *widget = new QWidget(this);
    widget->setLayout(mainLayout);
    setCentralWidget(widget);

    //设置窗口背景为灰色
    setPalette(Qt::gray);
    //设置窗口在电脑屏幕上居中
    QDesktopWidget *desktopWidget = QApplication::desktop();
    int w = (desktopWidget->width() - this->width()) / 2;
    int h = 5;
    move(w, h);

    //初始化
    status = STATUS_OFF;
    nextTetrisBox->updateNextTetris(tetris);
    setWindowTitle(tr("Game_Tetris - OFF"));
    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(onTimer()));
}

MainWindow::~MainWindow()
{

}

//相应键盘事件
void MainWindow::keyPressEvent(QKeyEvent *event)
{
    //W键-进行旋转并更新游戏窗口内容
    if (event->key() == Qt::Key_W)
    {
        if (tetris.rotate())
        {
            //需要游戏状态为:正常进行
            if (status == STATUS_ON)
            {
                tetrisBox->updateTetris(tetris);
            }
        }
    }
    //A键-将方块向左移动并更新游戏窗口内容
    else if (event->key() == Qt::Key_A)
    {
        //需要游戏状态为:正常进行
        if (status == STATUS_ON)
        {
            if (tetris.moveToLeft())
            {
                tetrisBox->updateTetris(tetris);

            }
        }
    }
    //S键-将方块向下移动并更新游戏窗口内容
    else if (event->key() == Qt::Key_S)
    {
        //需要游戏状态:正常进行
        if (status == STATUS_ON)
        {
            if (tetris.moveToBottom())
            {
                tetrisBox->updateTetris(tetris);
                nextTetrisBox->updateNextTetris(tetris);
                updateScore();
            }
            else    //游戏结束
            {
                //计时器停止
                timer->stop();
                //输出结束提示
                QString str;
                str +=  QString("Game Over!\nYour Score is: %1!").arg(tetris.getScore());
                QMessageBox::information(this, tr("Game Over"), str);
                //更改游戏状态为:游戏结束
                status = STATUS_END;
                setWindowTitle(tr("Game_Tetris - END"));
            }
        }
    }
    //D键-将方块向右移动并更新游戏窗口内容
    else if (event->key() == Qt::Key_D)
    {
        //需要游戏状态为:正常进行
        if (status == STATUS_ON)
        {
            if (tetris.moveToRight())
            {
                tetrisBox->updateTetris(tetris);
            }
        }
    }
    //H键-开始游戏
    //不同状态的相应:
    //之前状态    之后状态
    //游戏暂停 -> 正常进行
    //还未开始 -> 正常进行
    //游戏结束 -> 正常进行
    else if (event->key() == Qt::Key_H)
    {
        if (status == STATUS_PAUSE)
        {
            timer->start(500);
            status = STATUS_ON;
            setWindowTitle(tr("Game_Tetris - ON"));
        }
        else if (status == STATUS_OFF)
        {
            //初始化窗口视图
            tetris.createBlock();
            tetrisBox->updateTetris(tetris);
            nextTetrisBox->updateNextTetris(tetris);
            updateScore();

            status = STATUS_ON;
            setWindowTitle(tr("Game_Tetris - ON"));
            timer->start(500);
        }
        else if (status == STATUS_END)
        {
            //初始化tetris
            tetris.clear();
            tetris.createBlock();
            tetrisBox->updateTetris(tetris);
            nextTetrisBox->updateNextTetris(tetris);
            updateScore();

            status = STATUS_ON;
            setWindowTitle(tr("Game_Tetris - ON"));
            timer->start(500);
        }
    }
    //J键-游戏暂停
    else if (event->key() == Qt::Key_J)
    {
        //需要游戏状态为:正常进行
        if (status == STATUS_ON)
        {
            timer->stop();
            status = STATUS_PAUSE;
            setWindowTitle(tr("Game_Tetris - PAUSE"));
        }
    }
    //C键-重新开始游戏
    else if (event->key() == Qt::Key_C)
    {
        timer->stop();
        tetris.clear();
        tetrisBox->updateTetris(tetris);
        nextTetrisBox->updateNextTetris(tetris);
        updateScore();
        status = STATUS_OFF;
        setWindowTitle(tr("Game_Tetris - OFF"));

    }
    //M键-关闭游戏
    else if (event->key() == Qt::Key_M)
    {
        close();
    }

}

void MainWindow::onTimer()
{
    if(tetris.moveToBottom())
    {
        tetrisBox->updateTetris(tetris);
        nextTetrisBox->updateNextTetris(tetris);
        updateScore();
    }
    else
    {
        timer->stop();
        QString str;
        str +=  QString("Game Over!\nYour Score is: %1!").arg(tetris.getScore());
        QMessageBox::information(this, tr("Game Over"), str);
        status = STATUS_END;
        setWindowTitle(tr("Game_Tetris - END"));
    }
}

void MainWindow::updateScore()
{
    QString str;
    int score = tetris.getScore();
    str += QString("%1").arg(score);
    scoreLabel->setText(str);
}

//若窗口最小化就停止计时器
void MainWindow::changeEvent(QEvent *event)
{
    if (event->type() != QEvent::WindowStateChange)
    {
        return;
    }
    if (windowState() == Qt::WindowMinimized)
    {
        timer->stop();
    }
}

main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • C++实现俄罗斯方块游戏

    本文实例为大家分享了C++实现俄罗斯方块游戏的具体代码,供大家参考,具体内容如下 使用VS2017编译 思路: 1.打印出游戏地图,也就是设计游戏地图类game_interdace,包括设计游戏开始界面的函数,游戏地图界面的函数,游戏结束界面的函数,以及设计一些辅助函数如(设置光标为目标点,改变颜色,隐藏光标)来完成上述设计. 2.设计方块图形类,包括生成图形,清理图形,图形移动,图形停止的处理,图形的消失(实质是得分)等. #include <iostream> #include<co

  • linux环境下C++实现俄罗斯方块

    本文实例为大家分享了C++实现俄罗斯方块的具体代码,供大家参考,具体内容如下 本程序的运行环境是linux,用到了多线程.创建了一个用来绘图的线程和一个获取按键的线程.程序中有一些需要改善的地方,比如336-338行定义的全局变量以及声明的对象.本来声明的Block和Table对象应该在main函数里面,然后将这两个对象作为参数传递给线程函数getkey.但是好像只能传递一个对象参数给线程函数.希望高手能够对程序进行改进. ps:由于用到了多线程,而pthread不是linux的默认库,所以编译

  • C++实现俄罗斯方块(windows API)

    本文分享的这些俄罗斯方块代码是我最近放假在家里自己写的,虽然以前有过看别人写的代码,但是那个游戏代码好像不是很全面,因为无法实现全部的方块和实现随机的产生任意方向的方块,现在也基本上是忘光了当时的代码,下面的这些代码是我最近写的,没有参考其他人的代码,真正写俄罗斯方块起来感觉真的是挺难的,关键是在于方块的旋转.当然下面的代码仅仅是一个框架,只能够实现大致上的功能,还不全面,贴出来和大家交流学习. 编译器是code::block  +  MinGW ,感觉CB这个IDE真的是太强大,太棒了,下面的

  • VC++ 6.0 C语言实现俄罗斯方块详细教程

    今天把我之前写的大作业分享一下吧,并教你们如何实现,希望你们看了前面的教程也能自己写一个. 1.要先下载一个 graphics.h 的头文件来绘图. 2.初始化窗口:initgraph(x, y);这是先创建一个窗口的函数,以左上角为(0,0),向右为x轴,向下为y轴,其中x表示长x个单位,y表示宽y个单位. 3.关闭图像窗口:closegraph();结束时用来关闭用的. 4.按任意键继续:getch();这个就和getchar();差不多,为了防止以运行完就关了,这样能停顿一下,他的头文件是

  • C++俄罗斯方块游戏 无需图形库的俄罗斯方块

    本文实例为大家分享了C++俄罗斯方块游戏的具体实现代码,供大家参考,具体内容如下. #include<stdio.h> #include<stdlib.h> #include<windows.h> #include<time.h> #include<conio.h> #define MOD 28 #define SIZE_N 19 #define SIZE_M 12 int cur_x,cur_y; int score,mark,next,map

  • C++实现俄罗斯方块

    本文实例为大家分享了C++实现俄罗斯方块的具体代码,供大家参考,具体内容如下 工具:vc++2010,图库:EasyX 先看效果图片 纯手写,没有面向对象思想,看全部源码 #include <stdio.h> #include <graphics.h> #include <time.h> #include <conio.h> #define BLOCK_COUNT 5 #define BLOCK_WIDTH 5 #define BLOCK_HEIGHT 5

  • C++控制台实现俄罗斯方块游戏

    之前学了些C++的课程,一直想着说编点小游戏,可是MFC又不想学,所以就只能变成控制台的小游戏. 俄罗斯方块一定是很多人小时候玩过的游戏.接下来就说说设计想法. 主要实现,选择游戏的等级,加速下降,不同形状不同颜色,暂停和退出功能. 首先是类的设计. class Box { private: int map[23][12];//画面坐标,记录有方块的点,也是游戏界面 int hotpoint[2];//当前活动的点,所有图形都是以此为基准绘制的 int top;//当前最高位置 int poin

  • 使用C++一步步实现俄罗斯方块

    一.实验介绍 1.1 实验内容 本节实验我们进行设计俄罗斯方块前的思路分析,以及介绍ncurses 库的使用方法. 1.2 实验知识点 C++ 编程基础 ncurses 库的使用 俄罗斯方块逻辑设计 1.3 实验环境 xface 终端 g++ 编译器 ncurses 库 1.4 适合人群 本课程难度一般,适合有 C++ 编程基础,对游戏设计.逻辑分析感兴趣的同学. 1.5 代码获取 git clone https://github.com/Gamerchen/game_zero.git 二.开发

  • C++制作俄罗斯方块

    缘起: 在玩Codeblocks自带的俄罗斯方块时觉得不错,然而有时间限制.所以想自己再写一个. 程序效果: 主要内容: 程序中有一个board数组,其中有要显示的部分,也有不显示的部分,不显示的部分都存储1. 如下图: shape采用4*4数组(shape)保存.如: 0 0 0 0 0 1 0 0 1 1 1 0 0 0 0 0 另外用变量row和column保存shape数组左上角在board中的位置. 每次下落或左右移动,先对row和column做出改变,然后检测当前row和column

  • 使用C++一步步实现俄罗斯方块后续

    一.实验简介 1.1 实验内容 本节实验我们将实现俄罗斯方块主要函数的设计,完成基本功能并运行. 1.2 实验知识点 窗口的绘制 方块类的设计 旋转算法 移动.消除函数 1.3 实验环境 xface 终端 g++ 编译器 ncurses 库 1.4 编译程序 编译命令要加上 -l 选项引入 ncurses 库: g++ main.c -l ncurses 1.5 运行程序 ./a.out 1.6 运行结果 二.实验步骤 2.1 头文件 首先包含头文件以及定义一个交换函数和随机数函数,后面用到(交

随机推荐