Qt-俄罗斯方块

头文件:

//Tetris.h
#ifndef ELUOSIWIDGET_H
#define ELUOSIWIDGET_H

#include <QtGui/QWidget>
#include <QPainter>
#include <QPaintEvent>
#include <QKeyEvent>
#include <cstring>
#include <ctime>

#define REC_SIZE 25     //方块大小
#define SCENE_W 16      //场景列数
#define SCENE_H 10      //场景行数

enum direction{UP,DOWN,LEFT,RIGHT,SPACE};

typedef struct {
    int pos_x; //方块x坐标
    int pos_y; //方块y坐标
}REC_Point;

class eluosiWidget : public QWidget
{
    Q_OBJECT

signals:
    void GameOver();    //游戏结束信号
    void CurrentScore(int);   //游戏当前分数
public slots:
    void StartGame();   //游戏开始
    void PlayGame();    //恢复游戏
    void PauseGame();   //暂停游戏
    void SetSpeed(int level);//设置速度等级
    void SetHard(int level);//设置是否增加难度
public:
    eluosiWidget(QWidget *parent = 0);    //构造函数
    ~eluosiWidget();                      //析构函数
    void weizhi(int x,int y,int tx,direction direct); //位置变换
    void paintEvent(QPaintEvent *event);  //场景绘制
    void change(int x,int y,int num,int state);     //方块变换
    void clear(int x,int y,int num);        //清除当前位置信息
    void move(int hang,direction direct);//部分移动
    void SetLevel();//设置难度等级
protected:
    void timerEvent(QTimerEvent *event);  //定时设置
    void keyPressEvent(QKeyEvent *event); //键盘事件
private:
    int scene_num[SCENE_W][SCENE_H];//场景数据
    REC_Point rpoint[4]; //定义四个方块的位置
    int REC_tx[2];//定义方块的图形
    int timerid1,timerid2;//记录两个定时器id
    int speed_ms,fresh_ms;//speed_ms记录下落速度,fresh_ms设置窗体刷新速度
    int score;//分数
    bool Pauseflag;//暂停标志
    bool Levelflag;//难度标志
    int HardLevel;//难度等级
};

#endif // ELUOSIWIDGET_H

实现:

//Tetris.cpp
#include "Tetris.h"

int tx_code[][4]={{456,258,456,258},{142,142,142,142},{246,268,123,248},{128,467,289,346},
                  {238,146,278,469},{247,126,247,126},{269,234,269,234}};//图形代码

eluosiWidget::eluosiWidget(QWidget *parent)
    : QWidget(parent)
{
    this->resize(SCENE_H*REC_SIZE,SCENE_W*REC_SIZE);  //设置窗口大小
    StartGame();  //开始游戏
}

eluosiWidget::~eluosiWidget()
{
    ;
}

void eluosiWidget::StartGame()       //初始化
{
    for(int i=0;i<SCENE_W;i++)  //清空舞台信息
        memset(scene_num[i],0,sizeof(int) * SCENE_H);
    score = 0; //分数初始化
    speed_ms = 800;fresh_ms = 50;//设置下落速度和刷新速度
    rpoint[0].pos_x = 1;rpoint[0].pos_y = SCENE_H/2;//设置主方块位置信息
    srand(time(0));REC_tx[0] = rand()%7;REC_tx[1] = rand()%7;//随机出现第一个图形
    change(rpoint[0].pos_x,rpoint[0].pos_y,tx_code[REC_tx[0]][0],2);
    Pauseflag = false;Levelflag=false;
    PlayGame();     //开始下落

}

void eluosiWidget::change(int x, int y, int num,int state)        //设置本次位置信息
{
   int temp = num;
   for(int i=1;i<4;i++){
        rpoint[i].pos_x=x-1+(num%10-1)/3;rpoint[i].pos_y=y-1+(num%10-1)%3;
        scene_num[rpoint[i].pos_x][rpoint[i].pos_y]=state;
        num = num/10;
    }
   scene_num[x][y]=state;
   rpoint[0].pos_x = x;rpoint[0].pos_y = y;
   if(258 == temp){
        scene_num[x+2][y]=state;rpoint[2].pos_x=x+2;rpoint[2].pos_y=y;
    }
   else if(456 == temp){
        scene_num[x][y+2]=state;rpoint[2].pos_x=x;rpoint[2].pos_y=y+2;
    }
}

void eluosiWidget::clear(int x, int y, int num)     //清除上次位置信息
{
    if(258 == num)
        scene_num[x+2][y]=0;
    else if(456 == num)
        scene_num[x][y+2]=0;
    for(int i=0;i<3;i++){
        scene_num[x-1+(num%10-1)/3][y-1+(num%10-1)%3]=0;
        num = num/10;
    }
    scene_num[x][y] =0;
}

void eluosiWidget::weizhi(int x,int y,int tx,direction direct)
{                           //x,y是坐标,tx是7种形状,direct是方向
    static int temp_tx;bool temp_flag;    temp_flag = true;
    switch(direct){
    case UP: //变换方块动作
        for(int i=0;i<4;i++)        //判断方块是否允许变换
            temp_flag = temp_flag && rpoint[i].pos_y-1 >= 0 && rpoint[i].pos_x+1 < SCENE_W-1
                        && rpoint[i].pos_x+1 != 1 && rpoint[i].pos_y+1 < SCENE_H ;
        if(temp_flag){              //执行变换动作
            clear(x,y,tx_code[tx][temp_tx++]);if(temp_tx >= 4) temp_tx = 0;change(x,y,tx_code[tx][temp_tx],2);
        }break;
    case DOWN://下移
        for(int i=0;i<4;i++)        //判断是否允许下移
            temp_flag = temp_flag && scene_num[rpoint[i].pos_x+1][rpoint[i].pos_y] !=1 &&
                        scene_num[rpoint[i].pos_x][rpoint[i].pos_y] !=1 && rpoint[i].pos_x+1 < SCENE_W;
        if(temp_flag){              //执行下移动作
            clear(x,y,tx_code[tx][temp_tx]);change(x+1,y,tx_code[tx][temp_tx],2);
        }else{
            //落下后更改状态为静止
            change(x,y,tx_code[tx][temp_tx],1);
            //判断是否满行
            for(int i=0;i<SCENE_W;i++){
                for(int j=0;j<SCENE_H;j++){     //将满行的信息消除
                    if(scene_num[i][j]==0)
                        break;
                    else if(j==SCENE_H-1){
                        move(i,DOWN);//从第i行开始整体下移
                        emit CurrentScore(score*10);break;
                    }
                }
            }
            //判断是否结束游戏
            if(scene_num[0][y] == 1){
                killTimer(timerid1);killTimer(timerid2);
                emit GameOver();break;
            }
            //判断是否加难度
            if(Levelflag){
                SetLevel();
                Levelflag=false;
            }
            //重新构造一个方块
            rpoint[0].pos_x = 1;rpoint[0].pos_y = SCENE_H/2;//设置主方块位置信息
            REC_tx[0]=REC_tx[1];//随机出现第一个图形
            REC_tx[1] = rand()%7;
            change(rpoint[0].pos_x,rpoint[0].pos_y,tx_code[REC_tx[0]][0],2);
            temp_tx = 0;
        }
        break;
    case LEFT://左移
        for(int i=0;i<4;i++)        //判断是否允许左移
            temp_flag = temp_flag && scene_num[rpoint[i].pos_x][rpoint[i].pos_y-1] !=1 && rpoint[i].pos_y-1 >=0;
        if(temp_flag){              //执行左移动作
        clear(x,y,tx_code[tx][temp_tx]);change(x,y-1,tx_code[tx][temp_tx],2);
        }break;
    case RIGHT://右移
        for(int i=0;i<4;i++)        //判断是否允许右移
            temp_flag = temp_flag && scene_num[rpoint[i].pos_x][rpoint[i].pos_y+1] !=1 && rpoint[i].pos_y+1 < SCENE_H;
        if(temp_flag){              //执行右移动作
        clear(x,y,tx_code[tx][temp_tx]);change(x,y+1,tx_code[tx][temp_tx],2);
        }break;
    case SPACE://快速下移
        for(int j=0;j<SCENE_W;j++){
            for(int i=0;i<4;i++)        //判断是否允许下移
                temp_flag = temp_flag && scene_num[rpoint[i].pos_x+1][rpoint[i].pos_y] !=1 &&
                            scene_num[rpoint[i].pos_x][rpoint[i].pos_y] !=1 && rpoint[i].pos_x+1 < SCENE_W;
            if(temp_flag){              //执行下移动作
                clear(x+j,y,tx_code[tx][temp_tx]);change(x+j+1,y,tx_code[tx][temp_tx],2);
            }else
                break;
        }break;
    }
}

void eluosiWidget::paintEvent(QPaintEvent *event)
{
    //设置画笔
    QPainter painter(this);
    //刷新舞台
    for(int i=0;i<SCENE_W;i++){
        for(int j=0;j<SCENE_H;j++){
            if(scene_num[i][j] == 1){
                painter.setBrush(QBrush(Qt::blue,Qt::SolidPattern));
                painter.drawRect(j*REC_SIZE,i*REC_SIZE,REC_SIZE,REC_SIZE);
            }
            else if(scene_num[i][j] > 1){
                painter.setBrush(QBrush(Qt::red,Qt::SolidPattern));
                painter.drawRect(j*REC_SIZE,i*REC_SIZE,REC_SIZE,REC_SIZE);
            }
        }
    }
}

void eluosiWidget::timerEvent(QTimerEvent *event)
{
    if(!Pauseflag && timerid1==event->timerId()){
        weizhi(rpoint[0].pos_x,rpoint[0].pos_y,REC_tx[0],DOWN);//下移
    }
    if(!Pauseflag && timerid2==event->timerId())  this->update(); //刷新绘图
}

void eluosiWidget::keyPressEvent(QKeyEvent *event)  //键盘事件
{
    if(!Pauseflag)
        switch(event->key()){
        case Qt::Key_Up:        //按下方向键上时
            weizhi(rpoint[0].pos_x,rpoint[0].pos_y,REC_tx[0],UP);break;
        case Qt::Key_Down:        //按下方向键下时
            weizhi(rpoint[0].pos_x,rpoint[0].pos_y,REC_tx[0],DOWN);break;
        case Qt::Key_Left:        //按下方向键左时
            weizhi(rpoint[0].pos_x,rpoint[0].pos_y,REC_tx[0],LEFT);break;
        case Qt::Key_Right:        //按下方向键右时
            weizhi(rpoint[0].pos_x,rpoint[0].pos_y,REC_tx[0],RIGHT);break;
        case Qt::Key_Space:     //快速下移
            weizhi(rpoint[0].pos_x,rpoint[0].pos_y,REC_tx[0],SPACE);break;
        }
}

void eluosiWidget::move(int hang, direction direct)
{
    if(direct == UP){
        for(int i=0;i<hang;i++)
            for(int j=0;j<SCENE_H;j++)
                scene_num[i][j] = scene_num[i+1][j];
    }else if(direct == DOWN){
        for(int i=hang;i>0;i--)
            for(int j=0;j<SCENE_H;j++)
                scene_num[i][j] = scene_num[i-1][j];
    }
}

void eluosiWidget::SetHard(int level)
{
    HardLevel = level;
    Levelflag = true;
}

void eluosiWidget::SetSpeed(int level)  //设置速度等级
{
    speed_ms = 800 - level * 60;
    PauseGame();
    PlayGame();
}

void eluosiWidget::SetLevel()
{
    for(int i=0;i<HardLevel;i++){
        move(SCENE_W-1,UP);
        for(int j=0;j<SCENE_H;j++)
            scene_num[SCENE_W-1][j] = rand()%2;
    }
}

void eluosiWidget::PlayGame()
{
    timerid1 = startTimer(speed_ms);//设置下落速度
    timerid2 = startTimer(fresh_ms);//设置刷新速度
    Pauseflag = false;
}

void eluosiWidget::PauseGame()
{
    killTimer(timerid1);killTimer(timerid2);
    Pauseflag = true;
}

主函数:

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

其他版本:

http://blog.csdn.net/imxiangzi/article/details/50667532
https://www.jerryzone.cn/qt-teris/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值