Qt-俄罗斯方块

来源:互联网 发布:springmvc ajax json 编辑:程序博客网 时间:2024/05/01 16:40

头文件:

//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_OBJECTsignals:    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/