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

以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。

推薦閱讀:

    None Found