1. 程序简介:
俄罗斯方块是一款大家都熟系的小游戏,这里给大家一步一步的详细介绍如何用QT开发这个游戏,并通过这款游戏的开发练习,进一步熟系"qvector.h","qpoint.h", "qmap.h","qpainter.h", QTime, KeyEvent,QMediaPlaylist,QMediaPlayer 等的用法。
2. 程序说明:
2.1 程序界面:分游戏区,提示区,控制区
2.2 程序实现功能:
1) 绘制游戏区域;
2) 按开始按钮开始游戏;
3) 按方向键实现方块的左移,右移,翻转;
4) 按空格键实现方块移动到最底部;
5) 当一行排满之后,自动消行。消行后,自动记分。
6) 每满1000分后,自动升到下一级,每升一级,方块向下移动的速度加快;
7) 记录游戏时间;
8) 按暂停按钮暂停游戏;
9) 按结束按钮结束游戏;
10)单击音乐按扭打开/关闭背景音乐;
3. 程序设计
3. 1 创建项目
3.1.1 新建一个以QMainWindow 为基类的Qt Widgets Application,取名 Teris;
3.1.2. 构建项目
1)单击项目模式,在弹出的窗口中选择构建套件,后按Configure Project 按扭。
构建完成后,程序处于可编译状态。
3.2 UI设计
3.2.1 移除窗口中的菜单栏,状态栏;
3.2.2 按下面示意图来设计窗体。
注意:
a. 主窗体大小设置为1000*800;
b. widgetGameArea 窗体大小设为600*800;
c. 先设计排版好控件后,再按Gridlayout;
d. 3 个Pushbutton 和CheckBox 的Focus Policy 设置为NoFocus;
3.2.3 在mainwindow.cpp 中填加如下语句:
1 setFixedSize(1000,800); //设置窗体为固定大小2 setWindowTitle(tr("俄罗斯方块"));//设置窗体标题3.2.4 运行效果如下
3.3 创建方块类:
3.3.1 新建一个C++ Class 文件,取名为Item, 并勾选#include Widget, #include QObject , Add Q_OBJECT.
3.3.2 在item.h中添加头文件 ,定义方块类形枚举变量,在GameArea 类体中添加 public 变量,成员函数;
#ifndef ITEM_H#define ITEM_H#include #include #include "qvector.h"#include "qpoint.h"#include "qpainter.h"enum ITEM_TYPE{ITEM_1 = 0,//长条ITEM_2,//山字形ITEM_3,//手枪形1ITEM_4,//手枪形2ITEM_5,//田ITEM_6,//Z字形1ITEM_MAX,};class Item{public:Item(){}Item(ITEM_TYPE t,int nShape = 0); //类型和形状构造~Item(void){};void InitNew(int nSeed = 0); //根据随机因子nSeed, 初始化方块类形的种类及形状void InitItem(ITEM_TYPE t,int nShape = 0); //根据方块类形的种类及形状,初始化方块类形的坐标void ChangeShape(int nAdd = 1); //改变文块类形形状, 默认按顺续改变形状void AddPoints(QVector& points); //添加方块格子坐标void Move(int x,int y); //横向移动x格,竖向移动y格void MoveTo(int x,int y);//移动到位置(x,y)格void MoveDown(int nRow,int y);//第nRow行以上的部分下移y行,用在消格之后void Draw(QPainter& painter,int nStartX,int nStartY,int nW,int nH); //根据方块格子的起始位置座标,长,宽,画出方块格子void DeleteRow(int y); //删除第y行public:QVector mPoints;//方块类型4个方块格子的坐标QPoint mPos; //方块类型原点ITEM_TYPE mType;//方块类型,有6种类型int mShape; //方块形状,每个类型方块有1~4个形状态,};#endif // ITEM_H3.3.3 在item.cpp 中实现成员函数。
#include "item.h"#include Item::Item(ITEM_TYPE t,int nShape) //类型和形状构造{mPos=QPoint(0,0);// 初始化方块类型的原点坐标InitItem(t,nShape); // 根据方块类形的种类及形状,初始化方块类形的坐标}void Item::InitNew(int nSeed){if(nSeed == 0){//如果没有随机因子,就使用当前时间作随机因子qsrand(QTime::currentTime().msec()); //qsrand, 使用Seed 生成随机数。后面的Qrand 使用相同的随机数序列}else{//传入随机因子qsrand(nSeed);}ITEM_TYPE t = (ITEM_TYPE)(qrand()%ITEM_MAX); // 产生随机的方块类型int s = qrand()%4; // 产生随机的形状//qDebug()widgetGameArea,&GameArea::sigUpdateScore,this,&MainWindow::slotUpdateScore);connect(ui->widgetGameArea,&GameArea::sigUpdateLevel,this,&MainWindow::slotUpdateLevel);connect(ui->widgetGameArea,&GameArea::sigUdateTimeEslape,this,&MainWindow::slotUpdateTime);3.4.6 在mainwindow.cpp 中实现槽函数,slotUpdateScoe,slotUpdateLevel,slotUpdateTime
void MainWindow::slotUpdateScore(int nScore){ui->labelScore->setText(QString::number(nScore));}void MainWindow::slotUpdateLevel(int nSpeed){ui->labelSpeed->setText(QString::number(nSpeed));}void MainWindow::slotUpdateTime(int tplayed){int sec=tplayed/1000;ui->labelTime->setText(QString::number(sec)+mTime);}3.4.7 把Widgetgamearea 窗体提升为自定义类GameArea
3.5 提示区设计, 提示区主要包含一个窗体,用于产生和提示下一个方块。
3.5.1 新建一个C++ Clarss 文件 , 取名为NextArea , 并勾选#include Widget, #include QObject , Add Q_OBJECT
3.5.2 在nextarea.h 中 添加 "item.h" 头文件, 并在类体中添加如下代码
class NextArea{Q_OBJECTpublic:explicit NextArea(QWidget *parent = nullptr); //构造函数protected:void paintEvent(QPaintEvent *); //绘图事件public slots:void slotUpdateNextItem(ITEM_TYPE t,int nShape); //产生下一个方块的槽函数private:Item mItem; //item 类变量};
3.5.3 在nextarea.cpp 中添加类的成员函数
void NextArea::paintEvent(QPaintEvent *){QPainter painter(this);painter.setBrush(QColor("#FFDEAD"));painter.setPen(QPen(QColor(Qt::black),1));int xStart = 80;//为了绘制在显示下一个方块区域的中部int yStart = 15;int w = 20;int h = 20;foreach (QPoint pt, mItem.mPoints){int x = xStart + pt.x() * w;int y = yStart + pt.y() * h;painter.drawRect(x, y, w, h);}update();}void NextArea::slotUpdateNextItem(ITEM_TYPE t, int nShape){mItem.InitItem(t,nShape);}3.5.3 在maiwindow.cpp 中添加头文件 nextarea.h, 在构造函数中添加如下代码
//GameArea通过信号sigUpdateNextItem 通知 NextArea 刷新下一个元素connect(ui->widgetGameArea,&GameArea::sigUpdateNextItem,ui->widgetNextArea,&NextArea::slotUpdateNextItem);3.5.4 提升nextarea 窗口为NextArea 类
3.6 操作区程序设计:
3.6.1 背景音乐:
3.6.1.1 在程序目录下,创建一个文件夹,命名为media, 拷备3个mp3 音乐到此文件夹下,并改名子为1.mp3, 2.mp3, 3.mp3
3.6.1.2 在teris.pro 添加 QT +=multimedia
3.6.1.3 在mainwindow.h 中添加头文件 QMediaPlaylist 和 QMediaPlayer. 并定义私有变量
QMediaPlaylist *Playlist;QMediaPlayer *player;3.6.1.4 在Mainwindow.cpp 的构造函数中, 添加如下代码
Playlist =new QMediaPlaylist; //创建新的播放清单player=new QMediaPlayer; //创建新的播放器Playlist->addMedia(QUrl::fromLocalFile("D:/MyQT/Teris/media/1.mp3")); //往播放清单中添加音乐文件Playlist->addMedia(QUrl::fromLocalFile("D:/MyQT/Teris/media/2.mp3"));Playlist->addMedia(QUrl::fromLocalFile("D:/MyQT/Teris/media/3.mp3"));Playlist->setCurrentIndex(0); //设置默认播放开始位置Playlist->setPlaybackMode(QMediaPlaylist::Loop); //设置循环播放player->setPlaylist(Playlist); //播放清单导入播放器player->play(); //播放器开播
3.6.1.5 单击Checkbox , 添加槽,
void MainWindow::on_checkBox_stateChanged(int arg1){if(arg1)player->play();elseplayer->stop();}3.6.2 控制按键设计:
3.6.2.1 在mainwindow.h 中添加私有变量:
bool Gamestatus; //记录游戏状态int mTime; //记录游戏时间3.6.2.2 在mainwindow.cpp 的构造函数添加语名,初始化按键和游戏状态
ui->pbPause->setEnabled(false);ui->pbStop->setEnabled(false);ui->checkBox->setChecked(true);Gamestatus=true;3.6.2.3 分别添加3个按键的槽函数
void MainWindow::on_pbStart_clicked(){Gamestatus=true;ui->widgetGameArea->NewGame();ui->pbStart->setEnabled(false);ui->pbPause->setEnabled(true);ui->pbStop->setEnabled(true);}void MainWindow::on_pbPause_clicked(){ui->widgetGameArea->PauseGame(Gamestatus);bool ok;if(Gamestatus){ui->pbPause->setText(tr("重新开始"));Gamestatus=false;mTime=(ui->labelTime->text()).toInt(&ok,10);}else{ui->pbPause->setText(tr("暂停"));Gamestatus=true;}}void MainWindow::on_pbStop_clicked(){ui->widgetGameArea->StopGame();ui->pbStop->setEnabled(false);ui->pbStart->setEnabled(true);ui->pbPause->setEnabled(false);}3.6.2.4 添加键盘事件, 响应按键动作, 在mainwindow.h 中添加头文件KeyEvent 和KeypressEvent
protected:void keyPressEvent(QKeyEvent *e);3.6.2.5 在mainwindow.cpp , 实现函数
void MainWindow::keyPressEvent(QKeyEvent *e){ui->widgetGameArea->KeyPressed(e->key());QMainWindow::keyPressEvent(e);}
介绍完成,运行程序玩起