QT项目一:俄罗斯方块

用QT开发小游戏-俄罗斯方块,是比较经典的项目,网上有很多资源以及源码。

可以参考以下链接:

https://blog.csdn.net/u012234115/article/details/45966479

https://blog.csdn.net/dpsying/article/details/53576917

项目目录:

QT项目一:俄罗斯方块_第1张图片 

1. widget.h文件

#ifndef WIDGET_H
#define WIDGET_H

#include 

const int BLOCK_SIZE=25; //单个方块单元的边长
const int MARGIN=5; //场景边距
const int AREA_ROW=20; //场景行数
const int AREA_COL=12; //场景列数

//方向
enum Direction
{
    UP,
    DOWN,
    LEFT,
    RIGHT,
    SPACE
};

//定义边界信息
struct Border
{
    int ubound;
    int dbound;
    int lbound;
    int rbound;
};

//坐标
struct block_point
{
    int pos_x;
    int pos_y;
    //    block_point(int x,int y):pos_x(x),pos_y(y){}
};

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    void InitGame(); //初始化
    void StartGame(); //开始游戏
    void GameOver(); //游戏结束

    void ResetBlock(); //重置方块
    void BlockMove(Direction dir); //方块变动
    void BlockRotate(int block[4][4]); //方块旋转
    void CreateBlock(int block[4][4],int block_id); //产生方块
    void GetBorder(int block[4][4],Border &border); //计算边界
    void ConvertStable(int x,int y); //转换为稳定方块
    bool IsCollide(int x,int y,Direction dir); //判断是否会碰撞

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

    virtual void paintEvent(QPaintEvent *event); //场景刷新
    virtual void timerEvent(QTimerEvent *event); //定时器事件
    virtual void keyPressEvent(QKeyEvent *event); //键盘响应

private:
    Ui::Widget *ui;

private:
    int game_area[AREA_ROW][AREA_COL]; //场景区域,1表示活动的方块,2表示稳定的方块,0表示空
    block_point block_pos; //当前方块坐标
    int cur_block[4][4]; //当前方块形状
    Border cur_border; //当前方块边界
    int next_block[4][4]; //下一个方块形状
    bool isStable; //当前方块是否稳定了
    int score;  //游戏分数
    int game_timer; //方块下落计时器
    int paint_timer; //渲染刷新计时器
    int speed_ms; //下落时间间隔
    int refresh_ms; //刷新时间间隔

};

#endif // WIDGET_H

2. main.cpp文件 

#include "widget.h"

#include 

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

3.widget.cpp文件

#include 
#include 
#include 
#include 
#include 
#include "widget.h"
#include "ui_widget.h"

//定义图案代码和边界
//田字
int item1[4][4] =
{
    {0, 0, 0, 0},
    {0, 1, 1, 0},
    {0, 1, 1, 0},
    {0, 0, 0, 0}
};

//右L
int item2[4][4] =
{
    {0, 1, 0, 0},
    {0, 1, 0, 0},
    {0, 1, 1, 0},
    {0, 0, 0, 0}
};

//左L
int item3[4][4] =
{
    {0, 0, 1, 0},
    {0, 0, 1, 0},
    {0, 1, 1, 0},
    {0, 0, 0, 0}
};

//右S
int item4[4][4]=
{
    {0,1,0,0},
    {0,1,1,0},
    {0,0,1,0},
    {0,0,0,0}
};
//左S
int item5[4][4]=
{
    {0,0,1,0},
    {0,1,1,0},
    {0,1,0,0},
    {0,0,0,0}
};
//山形
int item6[4][4]=
{
    {0,0,0,0},
    {0,0,1,0},
    {0,1,1,1},
    {0,0,0,0}
};
//长条
int item7[4][4]=
{
    {0,0,1,0},
    {0,0,1,0},
    {0,0,1,0},
    {0,0,1,0}
};

//拷贝方块图案
inline void block_cpy(int dblock[4][4], int sblock[4][4])
{
    for(int i=0; i<4; i++)
    {
        for(int j=0; j<4; j++)
        {
            dblock[i][j] = sblock[i][j];
        }
    }
}

void Widget::InitGame()
{
    for(int i=0; i=0&&game_area[block_pos.pos_y+i][block_pos.pos_x+j]!=2) //注意场景数组不越界
                    game_area[block_pos.pos_y+i][block_pos.pos_x+j]=cur_block[i][j];
        break;
    case RIGHT:
        if(block_pos.pos_x+cur_border.rbound==AREA_COL-1||IsCollide(block_pos.pos_x,block_pos.pos_y,RIGHT))
            break;
        //恢复方块左场景,为了清除移动过程中的方块残留
        for(int i=cur_border.ubound;i<=cur_border.dbound;i++)
            game_area[block_pos.pos_y+i][block_pos.pos_x]=0;
        block_pos.pos_x+=1;
        //方块右移一格,拷贝到场景
        for(int i=cur_border.ubound;i<=cur_border.dbound;i++)
            for(int j=0;j<4;j++)
                if(block_pos.pos_x+j<=AREA_COL-1&&game_area[block_pos.pos_y+i][block_pos.pos_x+j]!=2) //注意场景数组不越界
                    game_area[block_pos.pos_y+i][block_pos.pos_x+j]=cur_block[i][j];
        break;
    case SPACE: //一次到底
        //一格一格下移,直到不能下移
        while(block_pos.pos_y+cur_border.dbound=1)
    {
        bool is_line_full=true;
        for(int j=0;j=1;k--)
                for(int j=0;j=0; i--)
    {
        for(j=0; j<4; j++)
        {
            if(block[i][j] == 1)
            {
                border.ubound = i;
                break;
            }
        }
    }

    //下边界
    for(i=0; i<4; i++)
    {
        for(j=0; j<4; j++)
        {
            if(block[i][j] == 1)
            {
                border.dbound = i;
                break;
            }
        }
    }

    //左边界
    for(j=3; j>=0; j--)
    {
        for(i=0; i<4; i++)
        {
            if(block[i][j] == 1)
            {
                border.lbound = j;
                break;
            }
        }
    }

    //右边界
    for(j=0; j<4; j++)
    {
        for(i=0; i<4; i++)
        {
            if(block[i][j] == 1)
            {
                border.rbound = j;
                break;
            }
        }
    }
}

void Widget::ConvertStable(int x, int y)
{
    for(int i=cur_border.ubound;i<=cur_border.dbound;i++)
        for(int j=cur_border.lbound;j<=cur_border.rbound;j++)
            if(cur_block[i][j]==1)
                game_area[y+i][x+j]=2; //x和y别搞反
}

bool Widget::IsCollide(int x, int y, Direction dir)
{
    int temp_block[4][4];
    block_cpy(temp_block, cur_block);

    Border temp_border;
    GetBorder(temp_block, temp_border);

    switch(dir)
    {
    case UP:
        BlockRotate(temp_block);
        GetBorder(temp_block, temp_border); //旋转后要重新计算边界
        break;

    case DOWN:
        y += 1;
        break;

    case LEFT:
        x -= 1;
        break;

    case RIGHT:
        x += 1;
        break;

    default:
        break;
    }

    for(int i=temp_border.ubound; i<=temp_border.dbound; i++)
    {
        for(int j=temp_border.lbound; j<=temp_border.rbound; j++)
        {
            if(game_area[y+i][x+j]==2&&temp_block[i][j]==1||x+temp_border.lbound<0||x+temp_border.rbound>AREA_COL-1)
                return true;
        }
    }

    return false;
}


Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //调整窗口尺寸布局
    resize(AREA_COL*BLOCK_SIZE+MARGIN*4+4*BLOCK_SIZE,AREA_ROW*BLOCK_SIZE+MARGIN*2);
    //初始化游戏
    InitGame();
}

Widget::~Widget()
{
    delete ui;
}

void Widget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);

    //画游戏场景边框
    painter.setBrush(QBrush(Qt::white, Qt::SolidPattern));
    painter.drawRect(MARGIN, MARGIN, AREA_COL*BLOCK_SIZE, AREA_ROW*BLOCK_SIZE);

    //画方块预告
    painter.setBrush(QBrush(Qt::blue, Qt::SolidPattern));
    for(int i=0; i<4; i++)
    {
        for(int j=0; j<4; j++)
        {
            if(next_block[i][j] == 1)
            {
                painter.drawRect(MARGIN*3+AREA_COL*BLOCK_SIZE+j*BLOCK_SIZE,MARGIN+i*BLOCK_SIZE,BLOCK_SIZE,BLOCK_SIZE);
            }
        }
    }

    //绘制得分
    painter.setPen(Qt::black);
    painter.setFont(QFont("Arial", 14));
    painter.drawText(QRect(MARGIN*3+AREA_COL*BLOCK_SIZE,MARGIN*2+4*BLOCK_SIZE,BLOCK_SIZE*4,BLOCK_SIZE*4),Qt::AlignCenter,"score: "+QString::number(score));

    //绘制下落方块和稳定方块,注意方块边线的颜色是根据setPen来的,默认黑色
    for(int i=0; itimerId() == game_timer)
        BlockMove(DOWN);

    //刷新画面
    if(event->timerId() == paint_timer)
        update();
}

void Widget::keyPressEvent(QKeyEvent *event)
{
    switch(event->key())
    {
    case Qt::Key_Up:
        BlockMove(UP);
        break;
    case Qt::Key_Down:
        BlockMove(DOWN);
        break;
    case Qt::Key_Left:
        BlockMove(LEFT);
        break;
    case Qt::Key_Right:
        BlockMove(RIGHT);
        break;
    case Qt::Key_Space:
        BlockMove(SPACE);
        break;
    default:
        break;
    }
}

 效果图

QT项目一:俄罗斯方块_第2张图片

你可能感兴趣的:(QT)