Qt浅谈之四十九俄罗斯方块(代码来自网络)

一、简介

      从网上下载了一个Qt实现的俄罗斯方块单机版的源码,觉得非常有意思,故以博客形式记录下来,以便慢慢来研究。在centos6.6下编译运行(注意程序运行需要读取pro目录的配置文件,若把编译目录选择在pro外的话运行会报错):

 

二、详解

1、部分代码

 

(1)main.cpp

#include <QApplication>
#include <QTextCodec>
#include <QCursor>

#include "TetrixWidget.h"

int main( int argc, char **argv )
{

    QApplication a( argc, argv );

    QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
    QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
    //则更换图标
    QCursor myCursor( QPixmap( GLOBAL_CURSOR_IMAGE ) ) ;
    QApplication::setOverrideCursor( myCursor ) ;
    //这个是因为要使用Phonon这里要设置一个名字,可能是考虑到版权相关的问题吧,不然会有一个警告
    //并无其他实际意义
    a.setApplicationName("MyTetrix Game");

    TetrixWidget widget ;
    widget.show();

    return a.exec();
}

(2)TetrixWidget.h

#ifndef TETRIXWIDGET_H
#define TETRIXWIDGET_H


#include <QDesktopWidget>
#include <QApplication>
#include <QWidget>
#include <QGraphicsView>
#include <QSettings>
#include <QStringList>
#include <QImage>
#include <QPoint>
#include <QKeyEvent>


#include "GameGraphicsScene.h"
#include "GameBackGroundItem.h"
#include "GameLogoImageItem.h"
#include "GameButtonItem.h"
#include "GameArrowItem.h"
#include "GameMovBackGrouItem.h"
#include "GameIntroductionItem.h"
#include "GameOptionItem.h"
#include "GameHighWinItem.h"

#include "GameGameSound.h"

#include "globaldefines.h"

/**************************************************************************
 *                        常量                                            *
 **************************************************************************/


/**************************************************************************
 *                          宏定义                                         *
 **************************************************************************/


/**************************************************************************
 *                            数据类型                                     *
 **************************************************************************/


/**************************************************************************
 *                             类声明                                      *
 **************************************************************************/

class TetrixWidget : public QWidget
{
    Q_OBJECT
signals:
    //发送信号给ArrowItem,改变其坐标到坐标索引的index
    void moveArrowat( int index ) ;

    //这个是遮蔽箭头item上面的箭头的信号
    //这个信号放在这个类里是因为,按钮弹出的Item会通过按Esc来返回,这样就不能再发信号还原
    //其状态
    void coverOnArowItemSignal( bool state ) ;

    /**********************这个是当游戏被停用时的发送的信号********************/
    //这个是当游戏被停用时的发送的信号
    //就是当鼠标点击电脑桌面其他位置时,就是我们平常所说的整个游戏软件失去焦点时。发送这个信号
    void gameDeactivateSignal() ;
public:
    TetrixWidget(QWidget *parent=0) ;
    ~TetrixWidget() ;

private:
    QGraphicsView *gameView ;
    GameGraphicsScene *gameScene ;

    void setTetrixWigAttribute() ;          //设置TetrixWidget类的属性

    void initGameSceneAndView() ;           //初始化游戏的场景与视图


    QSettings *configIni ;        //这个是用于读取配置文件指针
    //这是定义的一个表,用来存储图片名字与图片的指针
    //这个作为一个大的容器,所以图片都放在里面。便于之后用
    NameAndImageHash  nameImageHash ;

    //根据组名及每组对应的图片数目的A值来读取配置文件,并且加载图片文件。
    void initAndLoadImage( QString groupname, QString A_valueString ) ;

    void loadAllImageFile() ;      //加载所有的图片

    //这个坐标ponit用于取图片上某个坐标点的色素作为透明色,默认为QPoint( 0,0 )
    QImage *getTransImage( QImage *image , QPoint ponit = QPoint( 0,0 ) ) ;

    /*
    这个是处理所有的粉红色背景的图片,使只编程透明色背景
    */
    void dealPinkBackGroundImage( QString groupname, QString A_valueString ) ;

    /*
    这个是因为当第三层出现时,用户按下Esc键,要回到第二层游戏首页,
    所以在这里用这个hash表来记录
    */
    NumAndPointerHash numPointer ;
    /*
    这个是用来记录当前在第二层上面的Item,通过这个序号在NumAndPointerHash
    中查找Item对应的指针,默认为-1
    */
    int nowIndex ;
    /*
    这里是因为,这个设置的图片太小,要把下面的开始与退出按钮给隐藏掉,
    不然用户移动鼠标会误点到
    */
    void setSomeItemVisible( bool visible ) ;
    //从配置文件中读出所要的音量的值
    inline int getVolumeValueFromFile( QString groupname ,QString A_valueString ) ;
    //从配置文件中读取是否要设置全屏
    inline bool getFullScreenValueFromFile( QString groupname ,QString A_valueString ) ;


    /****************************最底层的Item******************************/
    GameLogoImageItem *logoImageItem ;
    void addGameLogoImageItem( ) ;           //添加GameLogoImageItem到场景去

    GameBackGroundItem *backGroundItem ;
    //这是定义的一个表,用来存储图片名字与图片的坐标
    //部分图片的坐标不需要写在配置文件,因为其默认坐标一直都是(0,0)
    NameAndPointHash namePointHash ;
    //根据组名及每组对应的图片数目的A值来读取配置文件,并且记录到namePointHash中去。
    void initNameAndPointHash( QString groupname ,QString A_valueString ) ;

    /****************************第二层的Item******************************/
    GameButtonItem *dianwoButton ;            //点我的广告按钮
    GameButtonItem *moregameButton ;          //更多的游戏按钮
    GameButtonItem *startgameButton ;         //开始游戏按钮
    GameButtonItem *instrgameButton ;         //游戏介绍按钮
    GameButtonItem *gameoptionButton ;        //游戏选项按钮
    GameButtonItem *gamehihgscButton ;        //游戏排行榜按钮
    GameButtonItem *exitgameButton ;          //退出游戏按钮
    GameArrowItem  *arrowItem ;               //箭头Item
    /*
    添加所有的第二层的Item,通过一个接口把所有的第二层的Item全部放进来,方便管理
    */
    void addAllSecondLayerItem() ;
    //分开进行添加这样不至于让一个函数变的很长
    void addDianWoButton() ;       //添加点我按钮
    void addMoreGameButton() ;     //添加更多的游戏按钮
    void addStartGameButton() ;    //添加开始游戏按钮
    void addInstrGameButton() ;    //添加游戏介绍按钮
    void addGameOptionButton() ;   //添加游戏选项按钮
    void addGameHihgscButton() ;   //添加游戏排行榜按钮
    void addExitGameButton() ;     //添加退出游戏按钮
    void addArrowItem() ;          //添加箭头Item
    /****************************第三层的Item******************************/

    GameMovBackGrouItem *movBacGrouItem ;    //动态背景图片
    GameIntroductionItem *introduItem ;      //游戏介绍Item
    GameOptionItem *optionItem ;             //游戏选项Item
    GameHighWinItem *highWinItem ;           //游戏排行榜Item

    /**************************游戏的背景音乐与音效的处理*************************/
    GameGameSound *gameSound ;      //游戏的背景音乐与音效
    void initGameGameSound() ;      //初始化游戏的背景音乐与音效

private slots:
    void addGameBackGroundItem( ) ;         //添加GameBackGroundItem到场景去

    void mouseOnStartgameButton( ) ;        //光标在开始游戏按钮
    void mouseOnInstrgameButton( ) ;        //光标在游戏介绍按钮
    void mouseOnGameOptionButton( ) ;       //光标在游戏选项按钮
    void mouseOnGameHihgscButton( ) ;       //光标在游戏排行榜按钮
    void mouseOnExitgameButton( ) ;         //光标在退出游戏按钮

    void clickOnStartgameButton( ) ;        //单击开始游戏按钮
    void clickOnInstrgameButton( ) ;        //单击游戏介绍按钮
    void clickOnGameOptionButton( ) ;       //单击游戏选项按钮
    void clickOnGameHihgscButton( ) ;       //单击游戏排行榜按钮
    void clickOnExitgameButton( ) ;         //单击退出游戏按钮

    /*
    这个是根据当前箭头序号来确定进入到哪个Item的槽函数
    */
    void clickOnButton( int index ) ;

    /*
    用户按Esc键返回到第二层,返回游戏首页的信号的槽函数
    */
    void backToSecondLaySlot( int index ) ;
    //这个是前景Item的退回到游戏首页的按钮的槽函数
    void backToGameHomeSlot() ;
protected:
    //事件过滤器
    bool eventFilter ( QObject * watched, QEvent * event ) ;
    void	resizeEvent ( QResizeEvent * event );
};

#endif // TETRIXWIDGET_H

(3)TetrixWidget.cpp

/************************************************************************
* 版权所有 (C)2011, 上海欣诺有限公司。
*
* 文件名称:  TetrixWidget.cpp
* 文件标识:
* 内容摘要:  TetrixWidget类的实现
* 其它说明:
* 当前版本: 1.0
* 作    者:
* 完成日期:
*
* 修改记录1:
*    修改日期:
*    版 本 号:
*    修 改 人:
*    修改内容:
* 修改记录2:…
************************************************************************/

#include "TetrixWidget.h"
#include <QDebug>

/**************************************************************************
 *                            常量                                        *
 **************************************************************************/



/**************************************************************************
 *                            宏                                          *
 **************************************************************************/


/**************************************************************************
 *                          数据类型                                       *
 **************************************************************************/



/**************************************************************************
 *                           全局变量                                      *
 **************************************************************************/



/**************************************************************************
 *                           局部函数原型                                  *
 **************************************************************************/

/**************************************************************************
 *                  类TetrixWidget实现--公有部分                          *
 **************************************************************************/

/**************************************************************************
* 函数名称: TetrixWidget
* 功能描述: 构造函数
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/


TetrixWidget::TetrixWidget(QWidget *parent)
    :QWidget(parent),nowIndex( -1 )
{
    //初始化,设置其读取ini为后缀的配置文件
    configIni = new QSettings( CONFIGUREPATH,QSettings::IniFormat ) ;
    //首先加载是两个logo文件
    initAndLoadImage( GROUPNAME_LOGO,LOGO_COUNT ) ;
    /*
    设置控件显示的参数,因为其大小是根据logo图片的大小还算的,所以要放在读取配置文件之后
    */
    setTetrixWigAttribute() ;
    //初始化视图的大小也是根据两个logo图片的大小来确定的,所以要放在读取配置文件之后
    initGameSceneAndView() ;

    addGameLogoImageItem() ;      //添加GameLogoImageItem到场景去
    /*
    只所以把GameLogoImageItem添加到场景去再加载所有的图片,
    是因为logo图片有个渐显的效果,可以利用这个间隙把所有的图片
    全部加载进来,该处理的出来掉。这样可以有效的利用时间,让用户感觉不到
    加载图片过程
    */
    loadAllImageFile() ;     //加载所有的图片
    /*
    根据组名及每组对应的图片数目的A值来读取配置文件,并且记录到namePointHash中去。
    */
    initNameAndPointHash( GROUPNAME_COORDINATE ,COORDINATE_COUNT) ;
}

/***********************************************************************
* 函数名称: ~TetrixWidget()
* 功能描述: 析构函数
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
*************************************************************************/

TetrixWidget::~TetrixWidget()
{
    //这个显示delete,qt都可以通过qt来进行delete的
    delete gameSound ;
}


/**************************************************************************
* 函数名称: setTetrixWigAttribute
* 功能描述: 设置TetrixWidget类的属性
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::setTetrixWigAttribute()
{
    /*
    这里是设置屏蔽窗口最大化的按钮的属性,在linux下没有效果,在windows有效果不知道为啥
    */
    this->setWindowFlags( Qt::Window
                          | Qt::WindowMinimizeButtonHint
                          | Qt::WindowCloseButtonHint );

    //设置居中屏幕显示
    QDesktopWidget* desktop = QApplication::desktop(); // =qApp->desktop();也可以
    /*
    这个是根据logo的大小来确定的,由于控件比图片多一个宽口管理其,所以height加40进行调整
    ,以达到初始显示在屏幕中间的效果
    */
    if( nameImageHash.contains( LOGO_1 ) )
    {
        int width = nameImageHash.value(LOGO_1)->size().width() ;
        int height = nameImageHash.value(LOGO_1)->size().height() + 40 ;
        move((desktop->width() - width)/2, (desktop->height() - height)/2);
    }
    //安装事件过滤器
    this->installEventFilter( this );

    setWindowTitle("俄罗斯方块单机版 V1.0");

}

/**************************************************************************
* 函数名称: initAndLoadImage
* 功能描述: 根据组名及每组对应的图片数目的A值来读取配置文件,并且加载图片文件。
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/

void TetrixWidget::initAndLoadImage(QString groupname, QString A_valueString)
{
    if( !groupname.isEmpty() )
    {
        configIni->beginGroup( groupname );
        configIni->setIniCodec( "UTF-8" );
        int count = configIni->value( A_valueString).toInt() ;

        QStringList keyslist = configIni->allKeys() ;
        //configIni->allKeys()因为这个里面有包含啦求数目的那条A值
        if( keyslist.count() == (count + 1) )
        {
            foreach( QString value,keyslist )
            {
                //如果为数目的A值,则不做处理
                if( QString::compare( value , A_valueString ) )
                {
                    QString imagePath = configIni->value( value ).toString() ;
                    QImage *iamge = new QImage( imagePath ) ;
                    //如果不能加载图片文件,则退出
                    if( iamge->isNull() )
                    {
                        QString errorString = QString("File :%1 is not exit !" ).arg(imagePath) ;
                        DEBUGP(  errorString ) ;
                        configIni->endGroup();
                        return ;
                    }
                    //把图片名字与图片加入到hash表中
                    nameImageHash.insert( value,iamge ) ;
                }
            }
        }
        else
        {
            DEBUGP( "Configure File Num Error !" ) ;
            configIni->endGroup();
            return ;
        }
        configIni->endGroup();
    }
}

/*************************************************************************
* 函数名称: initNameAndPointHash
* 功能描述: 根据组名及每组对应的图片数目的A值来读取配置文件,并且记录到namePointHash中去
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::initNameAndPointHash(QString groupname, QString A_valueString)
{
    if( !groupname.isEmpty() )
    {
        configIni->beginGroup( groupname );
        configIni->setIniCodec( "UTF-8" );
        int count = configIni->value( A_valueString ).toInt() ;
        QStringList keyslist = configIni->allKeys() ;
        //configIni->allKeys()因为这个里面有包含啦求数目的那条A值
        if( keyslist.count() == (count + 1) )
        {

            foreach( QString key,keyslist )
            {   //如果为数目的A值,则不做处理
                if( QString::compare( key , A_valueString ) )
                {
                    QPoint pos = configIni->value(key).toPoint() ;
                    //DEBUGP( pos ) ;
                    namePointHash.insert( key,pos ) ;
                }
            }

        }
        configIni->endGroup();
    }
}

/*************************************************************************
* 函数名称: getTransImage
* 功能描述: 这个坐标ponit用于取图片上某个坐标点的色素作为透明色,默认为QPoint( 0,0 )
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
QImage *TetrixWidget::getTransImage(QImage *image, QPoint ponit)
{
    //判断所取的点是否在图片内部
    if( image->valid( ponit ) )
    {
        QRgb  rgb = image->pixel( ponit );

        QVector<QRgb> rgbVector = image->colorTable () ;
        for (int i = 0; i < rgbVector.size(); ++i)
        {
             if( rgbVector.at(i) == rgb )
             {
                 /*
                注意这里如果要变成黑色背景的话就是QRgb rgb2 = QColor(0, 0, 0, 0).rgb() ;
                留意 rgb()与rgba()的区别
                */
                 QRgb rgb2 = QColor(0, 0, 0, 0).rgba() ;
                 image->setColor( i,rgb2 );
                 return image ;
             }
         }
    }
    return image ;
}


/*************************************************************************
* 函数名称: initGameSceneAndView
* 功能描述: 初始化游戏的场景与视图
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::initGameSceneAndView()
{
    gameScene = new GameGraphicsScene() ;
    gameScene->setBackgroundBrush(Qt::black);
    //这里要是不限制场景的大小的话,之后小鱼游动时,其场景会增大,之后显示就会移动
    //因为小鱼要被完全隐藏掉之后,才掉头重新开始游这样就可能增大场景,故再这里给写死
    gameScene->setSceneRect(0, 0, SCENEWIDTH, SCENEHEIGHT);
    gameView = new QGraphicsView(this) ;
    gameView->setScene(gameScene);

    //设置文字去锯齿显示
    gameView->setRenderHints(QPainter::Antialiasing
                         | QPainter::TextAntialiasing);

    //设置大小,跟logo图片的大小一样大,不能写死,这样灵活些
    if( nameImageHash.contains( LOGO_1 ) )
    {
        /*
        在这里把长宽进行微调,不然会出现在场景中滚动鼠标是,场景上下移动的问题
        */
        int width = nameImageHash.value(LOGO_1)->size().width()+ 2 ;
        int height = nameImageHash.value(LOGO_1)->size().height() + 2 ;
        gameView->resize( width,height );
    }
    //关闭水平滚动条与垂直滚动条
    gameView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    gameView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
}


/*************************************************************************
* 函数名称: loadAllImageFile
* 功能描述: 加载所有的图片
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::loadAllImageFile()
{
    //加载ModeWin组的文件
    initAndLoadImage( GROUPNAME_MODEWIN,MODEWIN_COUNT ) ;
    //加载DianWoWin组的文件
    initAndLoadImage( GROUPNAME_DIANWOWIN,DIANWOWIN_COUNT ) ;
    //加载OptionWin组的文件
    initAndLoadImage( GROUPNAME_OPTIONWID,OPTIONWID_COUNT ) ;
    //加载Box组的文件
    initAndLoadImage( GROUPNAME_BOX,BOX_COUNT ) ;
    //加载BackWin组的文件
    initAndLoadImage( GROUPNAME_BACKWIN,BACKWIN_COUNT ) ;
    //加载BombWin组的文件
    initAndLoadImage( GROUPNAME_BOMBWIN,BOMBWIN_COUNT ) ;
    //加载MainWin组的文件
    initAndLoadImage( GROUPNAME_MAINWIN,MAINWIN_COUNT ) ;
    //修改MustModify组A值所对应的图片,去掉其背景粉红色,变为透明背景
    dealPinkBackGroundImage( GROUPNAME_MUSTMODIFY,MUSTMODIFY_COUNT ) ;
}


/*************************************************************************
* 函数名称: dealPinkBackGroundImage
* 功能描述: 添加dealPinkBackGroundImage到场景去
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::dealPinkBackGroundImage(QString groupname, QString A_valueString )
{
    if( !groupname.isEmpty() )
    {
        configIni->beginGroup( groupname );
        configIni->setIniCodec( "UTF-8" );
        int count = configIni->value( A_valueString).toInt() ;

        QStringList keyslist = configIni->allKeys() ;
        //configIni->allKeys()因为这个里面有包含啦求数目的那条A值
        if( keyslist.count() == (count + 1) )
        {
            foreach( QString key,keyslist )
            {
                //如果为数目的A值,则不做处理
                if( QString::compare( key , A_valueString ) )
                {
                    //DEBUGP( key ) ;
                    //对图片进行处理,去掉粉红的背景
                    QImage *image = getTransImage( nameImageHash.value( key ) );
                    //重新发修改后的值加入到hash表中
                    nameImageHash.insert( key,image ) ;
                }
            }
        }
        //注意读完这个组一定要关闭,否则会影响到下面的读取
        configIni->endGroup();
    }
}

/*************************************************************************
* 函数名称: addGameLogoImageItem
* 功能描述: 添加GameLogoImageItem到场景去
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::addGameLogoImageItem()
{
    logoImageItem = new GameLogoImageItem() ;
    //
    connect(logoImageItem,SIGNAL(addGameBackGroundItem())
            ,this,SLOT(addGameBackGroundItem())) ;
    logoImageItem->setGameScene( gameScene,nameImageHash);
}

/*************************************************************************
* 函数名称: addAllSecondLayerItem
* 功能描述: 添加所有的第二层的Item,通过一个接口把所有的第二层的Item全部放进来,方便管理
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::addAllSecondLayerItem()
{
    //DEBUGP( "addAllSecondLayerItem" ) ;
    //点我广告的按钮
    addDianWoButton() ;
    //更多的游戏按钮
    addMoreGameButton() ;
    //开始游戏按钮
    addStartGameButton() ;
    //游戏介绍按钮
    addInstrGameButton() ;
    //游戏选项按钮
    addGameOptionButton() ;
    //游戏排行榜按钮
    addGameHihgscButton() ;
    //退出游戏按钮
    addExitGameButton() ;
    //箭头Item
    addArrowItem() ;
}


/*************************************************************************
* 函数名称: addArrowItem
* 功能描述: 添加箭头Item
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::addArrowItem()
{
    //箭头Item
    arrowItem = new GameArrowItem( MODEWIN_ARROW ) ;
    //在这里连接改变坐标的信号与槽
    connect(this,SIGNAL(moveArrowat(int)),arrowItem,SLOT(setPointListIndex(int))) ;
    //这个是根据当前箭头序号来确定进入到哪个Item的槽函数
    connect(arrowItem,SIGNAL(enterIntoButton(int)),this,SLOT(clickOnButton(int)));
    //通过这个信号返回到第二层----游戏首页
    connect(arrowItem,SIGNAL(backToSecondLay(int)),this,SLOT(backToSecondLaySlot(int)));
    arrowItem->setGameScene(gameScene,nameImageHash,namePointHash);
    /*
    这里为啦保持跟上面的一直,所以把设置Z轴的放在这里,其实不必要放在这里,
    因为箭头类是一个单独的类,只有一个对象在用
    */
    arrowItem->setZValue(1.0);

}
/*************************************************************************
* 函数名称: addExitGameButton
* 功能描述: 添加退出游戏按钮
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::addExitGameButton()
{
    //退出游戏按钮
    exitgameButton = new GameButtonItem( MODEWIN_EXIT ) ;
    connect(exitgameButton,SIGNAL(mouseOnMe()),
            this,SLOT(mouseOnExitgameButton())) ;
    connect(exitgameButton,SIGNAL(buttonClick()),this,SLOT(close())) ;
    exitgameButton->setGameScene(gameScene,nameImageHash,namePointHash);
    exitgameButton->setZValue(1.0);    //因为不是全部都在同一层,所有得分开来设置其Z轴的值
}

/*************************************************************************
* 函数名称: addGameHihgscButton
* 功能描述: 添加游戏排行榜按钮
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::addGameHihgscButton()
{
    //游戏排行榜按钮
    gamehihgscButton = new GameButtonItem( MODEWIN_HIGHSCORE ) ;
    connect(gamehihgscButton,SIGNAL(mouseOnMe()),
            this,SLOT(mouseOnGameHihgscButton())) ;
    connect(gamehihgscButton,SIGNAL(buttonClick()),this,SLOT(clickOnGameHihgscButton()));
    gamehihgscButton->setGameScene(gameScene,nameImageHash,namePointHash);
    gamehihgscButton->setZValue(1.0);    //因为不是全部都在同一层,所有得分开来设置其Z轴的值
}


/*************************************************************************
* 函数名称: addGameOptionButton
* 功能描述: 添加游戏选项按钮
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::addGameOptionButton()
{
    //游戏选项按钮
    gameoptionButton = new GameButtonItem( MODEWIN_OPTION ) ;
    connect(gameoptionButton,SIGNAL(mouseOnMe()),
            this,SLOT(mouseOnGameOptionButton())) ;
    connect(gameoptionButton,SIGNAL(buttonClick()),
            this,SLOT(clickOnGameOptionButton())) ;
    gameoptionButton->setGameScene(gameScene,nameImageHash,namePointHash);
    gameoptionButton->setZValue(1.0);    //因为不是全部都在同一层,所有得分开来设置其Z轴的值
}

/*************************************************************************
* 函数名称: addInstrGameButton
* 功能描述: 添加游戏介绍按钮
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::addInstrGameButton()
{
    //游戏介绍按钮
    instrgameButton = new GameButtonItem( MODEWIN_INSTRUCTION ) ;
    connect(instrgameButton,SIGNAL(mouseOnMe()),
            this,SLOT(mouseOnInstrgameButton())) ;
    connect(instrgameButton,SIGNAL(buttonClick())
            ,this,SLOT(clickOnInstrgameButton())) ;
    instrgameButton->setGameScene(gameScene,nameImageHash,namePointHash);
    instrgameButton->setZValue(1.0);    //因为不是全部都在同一层,所有得分开来设置其Z轴的值
}



/*************************************************************************
* 函数名称: addDianWoButton
* 功能描述: 添加点我按钮
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::addDianWoButton()
{
    //点我广告的按钮
    dianwoButton = new GameButtonItem( DIANWOWIN_BUTTON ) ;
    dianwoButton->setGameScene(gameScene,nameImageHash,namePointHash);
    dianwoButton->setZValue(1.0);    //因为不是全部都在同一层,所有得分开来设置其Z轴的值
}


/*************************************************************************
* 函数名称: addMoreGameButton
* 功能描述: 添加更多的游戏按钮
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::addMoreGameButton()
{
    //更多的游戏按钮
    moregameButton = new GameButtonItem( MODEWIN_MOREGAME ) ;
    moregameButton->setGameScene(gameScene,nameImageHash,namePointHash);
    moregameButton->setZValue(1.0);    //因为不是全部都在同一层,所有得分开来设置其Z轴的值
}


/*************************************************************************
* 函数名称: addStartGameButton
* 功能描述: 添加开始游戏按钮
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::addStartGameButton()
{
    startgameButton = new GameButtonItem( MODEWIN_START ) ;
    connect(startgameButton,SIGNAL(mouseOnMe()),
            this,SLOT(mouseOnStartgameButton())) ;
    connect(startgameButton,SIGNAL(buttonClick()),
            this,SLOT(clickOnStartgameButton())) ;
    startgameButton->setGameScene(gameScene,nameImageHash,namePointHash);
    startgameButton->setZValue(1.0);    //因为不是全部都在同一层,所有得分开来设置其Z轴的值
}
/*************************************************************************
* 函数名称: setSomeItemVisible
* 功能描述: 这里是因为,这个设置的图片太小,要把下面的开始与退出按钮给隐藏掉,
*           不然用户移动鼠标会误点到
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:控制这四个按钮的显示与隐藏
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::setSomeItemVisible(bool visible)
{
    startgameButton->setVisible( visible );
    exitgameButton->setVisible( visible );
    dianwoButton->setVisible( visible );
    moregameButton->setVisible( visible );
}


/*************************************************************************
* 函数名称: getVolumeValueFromFile
* 功能描述: 从配置文件中读出所要的音量的值
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:控制这四个按钮的显示与隐藏
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
inline int TetrixWidget::getVolumeValueFromFile(QString groupname, QString A_valueString)
{
    configIni->beginGroup( groupname );
    configIni->setIniCodec( "UTF-8" );
    int volume = configIni->value( A_valueString ).toInt() ;
    configIni->endGroup();
    return volume ;

}

/*************************************************************************
* 函数名称: getFullScreenValueFromFile
* 功能描述: 从配置文件中读取是否要设置全屏
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:控制这四个按钮的显示与隐藏
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
inline bool TetrixWidget::getFullScreenValueFromFile(QString groupname, QString A_valueString)
{
    configIni->beginGroup( groupname );
    configIni->setIniCodec( "UTF-8" );
    bool fullscreen = configIni->value( A_valueString ).toBool() ;
    configIni->endGroup();
    return fullscreen ;

}

/*************************************************************************
* 函数名称: initGameGameSound
* 功能描述: 初始化游戏的背景音乐与音效
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::initGameGameSound()
{
    int musicVolume = getVolumeValueFromFile( GROUPNAME_SETTINGS,SETTINGS_MUSIC ) ;
    int audioVolume = getVolumeValueFromFile( GROUPNAME_SETTINGS,SETTINGS_AUDIO ) ;
    gameSound = new GameGameSound( musicVolume,audioVolume ) ;
    gameSound->setGameSceneAndConfigF(gameScene,configIni);
}

/*************************************************************************
* 函数名称: addGameBackGroundItem
* 功能描述: 添加addGameBackGroundItem到场景去
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::addGameBackGroundItem()
{
    //在添加背景图片前先移除两个logo图片
    gameScene->removeItem( logoImageItem );
    backGroundItem = new GameBackGroundItem() ;
    backGroundItem->setGameScene( gameScene,nameImageHash );
    //添加所有的第二层的Item
    addAllSecondLayerItem() ;
    //初始化游戏的背景音乐与音效
    initGameGameSound();
}

/*************************************************************************
* 函数名称: mouseOnStartgameButton
* 功能描述: 光标在开始游戏按钮
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明: 5个Button发送过来的信号分别对应不同的槽函数,在槽函数中又分别发送同一信号
*          不同参数,这样觉得有点麻烦,一下子用啦5个槽函数,目前没有想到更好的办法。
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::mouseOnStartgameButton()
{
    //DEBUGP( 0 ) ;
    emit moveArrowat( 0) ;
}

/*************************************************************************
* 函数名称: mouseOnInstrgameButton
* 功能描述: 光标在游戏介绍按钮
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::mouseOnInstrgameButton()
{
    //DEBUGP( 1 ) ;
    emit moveArrowat( 1 ) ;
}
/*************************************************************************
* 函数名称: mouseOnGameOptionButton
* 功能描述: 光标在游戏选项按钮
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::mouseOnGameOptionButton()
{
    //DEBUGP( 2 ) ;
    emit moveArrowat( 2 ) ;
}

/*************************************************************************
* 函数名称: mouseOnGameHihgscButton
* 功能描述: 光标在游戏排行榜按钮
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::mouseOnGameHihgscButton()
{
    //DEBUGP( 3 ) ;
    emit moveArrowat( 3 ) ;
}

/*************************************************************************
* 函数名称: mouseOnExitgameButton
* 功能描述: 光标在退出游戏按钮
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::mouseOnExitgameButton()
{
    //DEBUGP( 4 ) ;
    emit moveArrowat( 4 ) ;
}


/*************************************************************************
* 函数名称: clickOnStartgameButton
* 功能描述: 单击开始游戏按钮
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::clickOnStartgameButton()
{
    movBacGrouItem =new GameMovBackGrouItem( MAINWIN_BACKGROUND ) ;
    //这个作为序号0记录到hash表中
    nowIndex = 0 ;
    numPointer.insert( nowIndex,(void *)movBacGrouItem ) ;
    connect( this,SIGNAL(coverOnArowItemSignal(bool)),
             gameScene,SIGNAL(changeCoveredStateSignal(bool))) ;
    //转发游戏窗口停用信号到场景中的游戏暂停信号
    connect(this,SIGNAL(gameDeactivateSignal()),gameScene,SIGNAL(gameDeactivateSignal())) ;
    //连接从场景中转发出来的回到游戏首页的信号与槽函数
    connect(gameScene,SIGNAL(backToGameHomeSignal()),
            this,SLOT(backToGameHomeSlot())) ;
    movBacGrouItem->setGameScene( gameScene,nameImageHash,namePointHash );
    movBacGrouItem->setZValue( 3.0 ) ;   //这个是作为第三层显示的
    //发送信号来还原之前改变的箭头Item的遮蔽状态
    emit coverOnArowItemSignal( true );
}


/*************************************************************************
* 函数名称: clickOnInstrgameButton
* 功能描述: 单击游戏介绍按钮
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::clickOnInstrgameButton()
{
    introduItem = new GameIntroductionItem( MODEWIN_HELP ) ;
    //这个作为序号1记录到hash表中
    nowIndex = 1 ;
    numPointer.insert( nowIndex,(void *)introduItem ) ;
    //返回游戏首页的信号的槽函数
    connect(introduItem,SIGNAL(backToSecondLay(int)),this,SLOT(backToSecondLaySlot(int))) ;
    connect( this,SIGNAL(coverOnArowItemSignal(bool)),
             gameScene,SIGNAL(changeCoveredStateSignal(bool))) ;
    introduItem->setGameScene( gameScene,nameImageHash );
    introduItem->setZValue( 3.0 ) ;   //这个是作为第三层显示的
    //发送信号来还原之前改变的箭头Item的遮蔽状态
    emit coverOnArowItemSignal( true );
}

/*************************************************************************
* 函数名称: clickOnGameOptionButton
* 功能描述: 单击游戏选项按钮
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::clickOnGameOptionButton()
{
    int musicVolume = getVolumeValueFromFile( GROUPNAME_SETTINGS,SETTINGS_MUSIC ) ;
    int audioVolume = getVolumeValueFromFile( GROUPNAME_SETTINGS,SETTINGS_AUDIO ) ;
    bool fullScreen = getFullScreenValueFromFile( GROUPNAME_SETTINGS,SETTINGS_FULLSCREEN) ;
    //DEBUGP( audioVolume ) ;
    optionItem = new GameOptionItem( OPTIONWIN_SETTING,musicVolume,audioVolume,fullScreen ) ;
    connect(optionItem,SIGNAL(backToSecondLay(int)),this,SLOT(backToSecondLaySlot(int))) ;
    connect( this,SIGNAL(coverOnArowItemSignal(bool)),
             gameScene,SIGNAL(changeCoveredStateSignal(bool))) ;
    //这个作为序号1记录到hash表中
    nowIndex = 2 ;
    numPointer.insert( nowIndex,(void *)optionItem ) ;
    optionItem->setGameScene( gameScene,nameImageHash,namePointHash );
    optionItem->setConfigureFile( configIni );
    optionItem->setZValue( 3.0 ) ;   //这个是作为第三层显示的
    /*
    这里是因为,这个设置的图片太小,要把下面的开始与退出按钮给隐藏掉,
    不然用户移动鼠标会误点到
    */
    setSomeItemVisible( false ) ;

    //发送信号来还原之前改变的箭头Item的遮蔽状态
    emit coverOnArowItemSignal( true );

}

/*************************************************************************
* 函数名称: clickOnGameHihgscButton
* 功能描述: 单击游戏排行榜按钮
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::clickOnGameHihgscButton()
{
    highWinItem = new GameHighWinItem( MODEWIN_HIGHWIN );
    connect(highWinItem,SIGNAL(backToSecondLay(int)),this,SLOT(backToSecondLaySlot(int))) ;
    connect( this,SIGNAL(coverOnArowItemSignal(bool)),
             gameScene,SIGNAL(changeCoveredStateSignal(bool))) ;
    //这个作为序号1记录到hash表中
    nowIndex = 3 ;
    numPointer.insert( nowIndex,(void *)highWinItem ) ;
    highWinItem->setGameScene( gameScene,nameImageHash,namePointHash );
    highWinItem->setZValue( 3.0 ) ;   //这个是作为第三层显示的

    //发送信号来还原之前改变的箭头Item的遮蔽状态
    emit coverOnArowItemSignal( true );
}

/*************************************************************************
* 函数名称: clickOnExitgameButton
* 功能描述: 单击退出游戏按钮
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::clickOnExitgameButton()
{
    //退出程序
    this->close() ;
}
/*************************************************************************
* 函数名称: clickOnButton
* 功能描述: 这个是根据当前箭头序号来确定进入到哪个Item的槽函数
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::clickOnButton(int index)
{
    switch( index )
    {
    case 0:
        clickOnStartgameButton() ;
        break ;
    case 1:
        clickOnInstrgameButton() ;
        break ;
    case 2:
        clickOnGameOptionButton() ;
        break ;
    case 3:
        clickOnGameHihgscButton() ;
        break ;
    case 4:
        clickOnExitgameButton() ;
        break ;
    default:
        break ;

    }
}


/*************************************************************************
* 函数名称: backToSecondLaySlot
* 功能描述: 用户按Esc键返回到第二层,返回游戏首页的信号的槽函数
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明: 通过这个当前箭头所对应的序号的值
*       比如说
*       0---->开始游戏
*       1---->游戏介绍
*       。。。。。。
*       在NumAndPointerHash表中查找相应的Item的指针的值
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::backToSecondLaySlot( int index )
{
    void * item ;
    /*
如果当用户本来就在第二层游戏首页时,这个时候却按下Esc键,这个时候这个item为空。
首先得判断hash表中有没这个key值
    */
    if( numPointer.contains( index ) )
    {
        item = numPointer.value( index ) ;
        if( item )
        {
            //因为每个类型的指针的类型是不同的,所以这里得这样分开来写
            switch( index )
            {
                case 0:
                    //在这里发送信号,先去删除动态珊瑚背景层之上的东西,也就是第四层与第五层的东西
                    //因为第四层与第五层都是作为动态珊瑚背景(第三层)的成员变量,所以在这里得在删除第三层前
                    //删掉第四层与第五层的东西
                    ((GameMovBackGrouItem *)item)->removeFourthAndFifthItemFun();
                    gameScene->removeItem( (GameMovBackGrouItem *)item );
                    delete ((GameMovBackGrouItem *)item);
                    //再次发送信号来还原之前改变的箭头Item的遮蔽状态
                    emit coverOnArowItemSignal( false );
                    break ;
                case 1:
                    gameScene->removeItem( (GameIntroductionItem *)item );
                    delete (GameIntroductionItem *)item ;
                    //再次发送信号来还原之前改变的箭头Item的遮蔽状态
                    emit coverOnArowItemSignal( false );
                    break ;
                case 2:
                    //使得四个按钮恢复显示
                    setSomeItemVisible( true ) ;
                    gameScene->removeItem( (GameOptionItem *)item );
                    delete (GameOptionItem *)item ;
                    //再次发送信号来还原之前改变的箭头Item的遮蔽状态
                    emit coverOnArowItemSignal( false );
                    break ;
                case 3:
                    gameScene->removeItem( (GameHighWinItem *)item );
                    delete (GameHighWinItem *)item ;
                    //再次发送信号来还原之前改变的箭头Item的遮蔽状态
                    emit coverOnArowItemSignal( false );
                    break ;
                case 4:
                    break ;
                default:
                    DEBUGP( "index error !" ) ;
                    break ;
            }
            //清空现在的记录,以便下次再进行切换
            nowIndex = -1 ;
            numPointer.remove( index ) ;
        }

    }

}


/*************************************************************************
* 函数名称: backToGameHomeSlot
* 功能描述: 这个是前景Item的退回到游戏首页的按钮的槽函数
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
void TetrixWidget::backToGameHomeSlot()
{
    //因为这个时候是进入游戏之后才可以看到游戏的前景
    backToSecondLaySlot( 0 ) ;
}
/*************************************************************************
* 函数名称: eventFilter
* 功能描述: 事件过滤器
* 访问的表:
* 修改的表:
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:这个是重载事件过滤器函数,通过这个函数判断,当鼠标移动到其他的软件的窗口时,
*         这个时候整个游戏软件被停用。在这个时候发送暂停游戏的消息
* 修改日期    版本号     修改人	     修改内容
* -----------------------------------------------
*
**************************************************************************/
bool TetrixWidget::eventFilter(QObject *watched, QEvent *event)
{
    if( watched == this )
    {
        //窗口停用,及一般人认为的失去焦点
        if(QEvent::WindowDeactivate == event->type())
        {
            //
            //DEBUGP( "eventFilter" ) ;
            emit gameDeactivateSignal() ;
            return true ;
        }
        else
        {
            return false ;
        }
    }
    return false ;
}
void TetrixWidget::resizeEvent(QResizeEvent *event)
{
    gameScene->setSceneRect(0, 0, gameView->width(), gameView->height());
}

 

三、总结

(1)上述代码是一个非常不错的项目例子,自己也在拜读代码(也有很多不懂的地方),并在实际工作中加以应用。
(2)上述代码已上传到CSDN:http://download.csdn.net/detail/taiyang1987912/9480721
(3)若有问题或建议,请留言,在此感谢!

  • 6
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
俄罗斯方块是一种经典的游戏,这里提供一份简易的Qt代码示例可以供参考: 首先,需要引入一些Qt的头文件: ```cpp #include <QMainWindow> #include <QKeyEvent> #include <QPainter> #include <QPixmap> #include <QTimer> ``` 然后,定义常量和数据结构: ```cpp const int BLOCK_SIZE = 20; // 方块边长 const int COLS = 10; // 游戏区列数 const int ROWS = 20; // 游戏区行数 struct Point { int x, y; }; ``` 接着,定义游戏区的数据和方块的数据: ```cpp class Window : public QMainWindow { Q_OBJECT public: Window(QWidget *parent = 0) : QMainWindow(parent) { setFixedSize(COLS * BLOCK_SIZE, ROWS * BLOCK_SIZE); mTimer.start(500); mEmptyBlock = QPixmap(BLOCK_SIZE, BLOCK_SIZE); mEmptyBlock.fill(Qt::black); mPlaying = false; } protected: void paintEvent(QPaintEvent*) { QPainter painter(this); painter.setBrush(Qt::NoBrush); painter.drawPixmap(0, 0, COLS * BLOCK_SIZE, ROWS * BLOCK_SIZE, mGameArea); for (int i = 0; i < 4; ++i) { painter.drawPixmap(mBlock[i].x * BLOCK_SIZE, mBlock[i].y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, mBlocks[mBlockType]); } } void keyPressEvent(QKeyEvent* ev) { if (!mPlaying) return; switch (ev->key()) { case Qt::Key_Left: if (canMove(-1, 0)) { moveLeft(); } break; case Qt::Key_Right: if (canMove(1, 0)) { moveRight(); } break; case Qt::Key_Down: if (canMove(0, 1)) { moveDown(); } break; case Qt::Key_Up: rotate(); break; } } private slots: void onTimer() { if (canMove(0, 1)) { moveDown(); } else { mergeBlock(); if (isGameOver()) { mPlaying = false; mBlocks.clear(); mGameArea = QPixmap(); QMessageBox::information(this, "Game Over", "Game Over"); return; } newBlock(); } repaint(); } private: bool mPlaying; QPixmap mGameArea; QTimer mTimer; QPixmap mEmptyBlock; QVector<QPixmap> mBlocks; QVector<Point> mBlock; int mBlockType; void moveLeft() { for (int i = 0; i < 4; ++i) { mBlock[i].x--; } } void moveRight() { for (int i = 0; i < 4; ++i) { mBlock[i].x++; } } void moveDown() { for (int i = 0; i < 4; ++i) { mBlock[i].y++; } } void rotate() { Point center = mBlock[1]; for (int i = 0; i < 4; ++i) { int x = mBlock[i].y - center.y; int y = mBlock[i].x - center.x; mBlock[i].x = center.x - x; mBlock[i].y = center.y + y; } } bool canMove(int dx, int dy) { for (int i = 0; i < 4; ++i) { int x = mBlock[i].x + dx; int y = mBlock[i].y + dy; if (x < 0 || x >= COLS || y >= ROWS) return false; if (y >= 0 && mGameArea.toImage().pixelColor(x * BLOCK_SIZE, y * BLOCK_SIZE) != QColor(0, 0, 0)) return false; } return true; } void mergeBlock() { for (int i = 0; i < 4; ++i) { mGameArea.copy(mBlock[i].x * BLOCK_SIZE, mBlock[i].y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, mBlocks[mBlockType], mBlock[i].x * BLOCK_SIZE, mBlock[i].y * BLOCK_SIZE); } for (int i = ROWS - 1; i >= 0; --i) { bool full = true; for (int j = 0; j < COLS; ++j) { if (mGameArea.toImage().pixelColor(j * BLOCK_SIZE, i * BLOCK_SIZE) == QColor(0, 0, 0)) { full = false; break; } } if (full) { mGameArea = QPixmap(mEmptyBlock) + mGameArea.copy(0, 0, COLS * BLOCK_SIZE, i * BLOCK_SIZE) + mGameArea.copy(0, (i + 1) * BLOCK_SIZE, COLS * BLOCK_SIZE, (ROWS - i - 1) * BLOCK_SIZE); } } } bool isGameOver() { for (int i = 0; i < 4; ++i) { if (mBlock[i].y < 0) return true; } return false; } void newBlock() { mBlockType = qrand() % mBlocks.size(); for (int i = 0; i < 4; ++i) { mBlock[i].x = mBlocks[mBlockType].width() / BLOCK_SIZE / 2 + i - 2; mBlock[i].y = 0; } } }; ``` 最后,在Qt应用程序的主函数中创建游戏窗口并运行即可: ```cpp int main(int argc, char **argv) { QApplication app(argc, argv); qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime())); Window w; w.show(); return app.exec(); } ``` 这就是一个简单的俄罗斯方块Qt代码示例,完整代码可以在网上找到。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乌托邦2号

博文不易,支持的请给予小小打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值