最新消息: USBMI致力于为网友们分享Windows、安卓、IOS等主流手机系统相关的资讯以及评测、同时提供相关教程、应用、软件下载等服务。

基于Qt的俄罗斯方块的设计与实现

IT圈 admin 35浏览 0评论

2024年3月26日发(作者:承古)

内 容 摘 要

俄罗斯方块是个比较经典的小游戏,它实现由四块正方形的色块

组成,然后存储在一个数组的四个元素中,计算机随机产生不同七种类

型的方块,根据计算机定时器控制它在一定的时间不停的产生,用户根

据键盘的四个方向键控制翻转、向左、向右和向下操作,(用信号和槽

函数的关联来实现对按键事件的控制)。然后程序根据这七种方块堆叠

成各种不同的模型。本设计大体分以下三部分:

第一部分是简介,用基本方法实现自己的俄罗斯方块游戏,介绍

游戏的基本概况及要实现的功能。第二部分是功能演示,验证游戏可否

按预想方案运行,验证运行流畅度,图形界面的美观度。第三部分是代

码分析,这里将展示整个游戏编程代码及接口函数。

本次设计用到的工具是基于UBUNTU下的QT软件,图行界面的处

理都是代码实现。

关 键 词

数组;定时器;信号;槽函数;QT

I

Design and implementation of Tetris, based on the QT

Name:Yiwenbo Teacher:Wangyiqin

Abstract

Tetris is a classic game, it consists of four square blocks of color, and

then stored in an array of four elements, the computer randomly generated

box of the seven types, according to the computer timer control it stop to

produce a certain amount of time, according to the four directions of the

keyboard keys to control flip, left, right and down operation (signal and slot

functions associated with control of key events). The program then based on

these seven box stacked into a variety of different models. This design is

generally divided into the following three parts: The first part is the

introduction to the basic methods to achieve their own game of Tetris. The

second part is the functional demonstration; verify that the game please run

the desired program. The third part is the game analysis, will show the entire

game programming code and an excuse to function. The design tool used is

based on the QT under UBUNTU software, the graph line interface

processing is code to achieve.

Key words

array; cell function; timer; signal;Qt

II

目 录

引言 ................................................... - 1 -

第一部分 简介 .......................................... - 3 -

1.1游戏功能 ......................................... - 3 -

1.2 游戏界面与控制 .................................. - 3 -

1.2.1游戏窗口 .................................... - 3 -

1.2.2方块形状 .................................... - 4 -

1.2.3键盘处理事件 ................................ - 4 -

1.2.4显示需求 .................................... - 4 -

第二部分 功能展示 ...................................... - 5 -

2.1 打开游戏 ........................................... - 5 -

2.2 进入游戏 ........................................ - 6 -

2.3游戏过关 ......................................... - 6 -

2.4 游戏暂停 ........................................ - 7 -

2.5 游戏退出 ........................................ - 8 -

第三部分 代码分析 ...................................... - 8 -

3.1 Tetrix工程 .................................... - 8 -

3.2 tetrixboard.h ................................. - 9 -

3.3 tetrixpiece.h ................................. - 10 -

3.4 tetrixwindow.h ................................ - 11 -

3.5 ...................................... - 12 -

III

3.6 ............................... - 13 -

3.7 ............................... - 14 -

3.7.1 显示框 .................................... - 14 -

3.7.2 功能按钮 .................................. - 15 -

3.7.3 信号与槽 .................................. - 16 -

3.7.4 游戏面板布局 .............................. - 16 -

.................................. - 17 -

3.8.1游戏初始化,复位的实现 ..................... - 18 -

3.8.2 游戏开始与暂停 ............................ - 19 -

3.8.3 按键控制游戏 .............................. - 22 -

3.8.4计时模块 ................................... - 23 -

3.8.5 方块的活动 ................................ - 24 -

3.8.6 过关与奖励 ................................ - 25 -

3.8.7 方块颜色控制 .............................. - 28 -

总结 .................................................. - 30 -

致谢 .................................................. - 30 -

参考文献 .............................................. - 30 -

IV

基于QT 的俄罗斯方块的设计与实现

081308233 易文波 指导教师:王义琴 讲师

引言

Qt是一个1991年由奇趣科技开发的跨平台C++图形用户界面应用程

序开发框架。它既可以开发GUI程式,也可用于开发非GUI程式,比如

控制台工具和服务器。Qt是面向对象语言,易于扩展,并且允许组件编

程。2008年,奇趣科技被诺基亚公司收购,QT也因此成为诺基亚旗下的

编程语言工具。

Qt支持下述平台:MS/Windows - 95、98、NT 4.0、ME、2000、XP 、

Vista和Win7 Unix/X11 - Linux、Sun Splaris、HP-UX、CompapTru64

UNIX、IBM AIX、SGI IRIX、FreeBSD、BSD/OS和其它很多X11平台

Macintosh - Mac OS X Embedded - 有帧缓冲(framebuffer)支持的嵌

入式Linux平台,Windows CE。

Qt具有以下优势:

面向对像,Qt 的良好封装机制使得Qt的模块化程度非常高,可重

用性较好,对于用户开发来说是非常方便的。 Qt 提供了一种称为

signals/slots的安全类型来替代callback,这使得各个元件之间的协

同工作变得十分简单。

丰富API,Qt包括多达250个以上的 C++ 类,还提供基于模板的

collections, serialization, file, I/O device, directory

- 1 -

management, date/time 类。甚至还包括正则表达式(在计算机科学

中,是指一个用来描述或者匹配一系列符合某个句法规则的字符串的单

个字符串。)的处理 功能。支持 2D/3D 图形渲染,支持OpenGL大量的

开发文档XML 支持Webkit 引擎的集成,可以实现本地界面与Web内容

的无缝集成。

俄罗斯方块是一款风靡全球的电视游戏机和掌上游戏机游戏,它曾

经造成的轰动与造成的经济价值可以说是游戏史上的一件大事。俄罗斯

方块游戏可以说是随计算机的发展而发展,并不断推陈出新演变出各种

类似游戏, 深受广大玩家喜爱。这个游戏有的简单, 有的复杂, 但其根

本原理是一样的都是对运动的方块进行组合, 来训练玩家的反应能力。

俄罗斯方块最早还是出现在PC机上,而我国的用户都是通过红白

机了解、喜欢上它的。现在QQ等游戏平台又将重新掀起这股让人沉迷

的俄罗斯方块风潮。对一般用户来说,它的规则简单,容易上手,且游

戏过程变化无穷,而在游戏平台上的对战模式更增加了它的娱乐性和挑

战性,使用户既能感受到游戏中的乐趣,也给用户提供了一个展现自己

高超技艺的场所。

本设计利用数组作为方块的数据结构,提出一种用C语言和C++来

实现的方法,实现基本的方块游戏功能,虽然不能实现联网对战功能,

但是可以通过设计实现本游戏巩固所学知识,增强动手能力,了解并熟

悉游戏软件的设计与开发过程。

本设计基于Qt,实现基本的方块游戏,所有图形界面均由代码实

现。通过验证各图形界面良好实现,游戏流畅运行。

- 2 -

第一部分 简介

1.1游戏功能

随机产生不同的形状(长条形、Z字形、反Z形、田字形、7字形、

反7形、T字型)下落填充给定的区域,若填满一行便消掉,相应区域

计数,此时分数有奖励,每消一行奖励十分,当方块出现一定的个数时,

过关,设置多个关卡,每关方块下落的速度不同,第一关默认下降速度

500ms(0.5s),以后每过一关速度递加,增加游戏难度。每出现一个方

块图形分数加七,如果使用快速下降功能(游戏中点击空格键)会有加

分,具体实现后面有详细介绍,若在游戏中各形状填满了给定区域,游

戏失败处于定格状态,此时可以重新开始游戏。游戏有暂停功能,当玩

家点暂停按钮时,游戏暂停,再次点击暂停按钮,游戏继续。

1.2 游戏界面与控制

1.2.1游戏窗口

良好的用户界面,有关数,分数,下一个方块预览,消除行数显示。

让方块在一定的区域内运动和变形,该区域用一种颜色表明,既用一种

颜色作为背景,这里为白色,而且该区域(游戏显示窗体)下陷,有层

次感,方块颜色随机,避免游戏单调。

- 3 -

1.2.2方块形状

良好的方块形状设计,方块简洁大方,大小适中,绘制七种常见的

基本图形(长条形、Z字形、反Z形、田字形、7字形、反7形、T字型),

各个方块要能实现它的变形,可设为顺时针或逆时针变形,本设计实现

了顺时针与逆时针两种旋转方式。七种方块随机产生示意图如图1-1。

随机产生一个数

随机数

反Z形

一字形

Z字形

7字形

反7形

倒T形

田字型

图1-1随机产生方块

1.2.3键盘处理事件

方块下落时,可通过键盘方向键(上、下、左、右、)空格键,D键

对该方块进行向上(顺时针变形),向下(逆时针变形)、向左、向右移动,

空格(直接降到底部),D(加快下降速度)。游戏面板上设置“Start”,

“Pause”,“Quite”三个按钮,分别用来控制游戏开始,暂停,退出功

能。

1.2.4显示需求

当不同的方块填满一行时可以消行,剩余方块向下移动并统计分

数。当方块下降一定的个数时过关。设置多个关卡,每关方块下落的速

- 4 -

度不同。游戏能在特定区域实时显示当前关卡,分数,消除行数,下一

个将要出现的图形。

第二部分 功能展示

本部分就方块游戏的功能配合截图进行检测与展示。

2.1 进入游戏

打开游戏,此时显示游戏的主窗口(由于Qt编程的可移植性,游

戏的窗口样式与当前平台或主题配色及样式保持一致),其中包括:

“Start”,“Quit”,“Pause”三个按钮,以及“NEXT”,“LEVEL”,“SCORE”,

“LINES REMOVED”四个显示框。中间空白长方形区域为方块活动区。

此时游戏处于初始化状态,各个显示卡内容均为0或空白,方块活动区

还没有出现方块。游戏状态截图如图2-1。

图2-1进入游戏

- 5 -

2.2 开始游戏

点击“Start”按钮,游戏开始,中间方块活动区域有方块出现并

下落,“LEVEL”由0变为1,“SCORE”也发生改变,截图中出现了两个

图形,所以分数显示为14,“NEXT”显示下一个将要出现的方块形状,

而由于还没有消除一行“LINES REMOVED”依然显示0,此时可通过键盘

控制游戏。如图2-2。

图2-2开始游戏

2.3游戏过关

当游戏中出现方块图形数达到25个时过关,此时“LEVEL”自动

变为2,方块下降速度加快,截图中显示内容可知,已经消除了十一行,

分数是702分,下一个将要出现的方块是7字形,同时由图可以看出方

块的形状颜色都是随机产生的。如图2-3。

- 6 -

图2-3游戏过关

2.4 游戏暂停

玩家中途暂停游戏时可以点击“Pause”,游戏会处于暂停状态,各

个显示窗口暂停计数,方块活动区域显示><,此时操作键盘游戏

将不会响应,当再次点击“Pause”按钮时游戏继续,如图2-4。

图2-4暂停游戏

- 7 -

2.5 游戏退出

游戏退出有两种情况,一种是方块堆满活动区且无法消除,游戏结

束,另一种情况是玩家中途退出,可以点击“Quit”按钮,或者直接关

闭装口,游戏退出再次开始时数据丢失,因为游戏会自动初始化。

通过检测,此俄罗斯方块游戏运行正常,各部分功能按照预期良好

实现,下面将具体分析各部分功能对应的代码、函数、信号、槽等。

第三部分 代码分析

3.1 Tetrix工程

每个程序都有一个工程,此工程下包含各种头文件以及对应的

函数,本工程包含的头文件有:tetrixboard.h,tetrixpiece.h,

tetrixwindow.h,三个函数,,

,后面将对各头文件及函数具体分析。由于游戏

代码量大,时间仓促,而且刚学QT,运用不是很熟练,本设计在老

师的指导下完成,有部分代码框架是老师代为实现,本人主要对

部分,包括游戏各功能的实现,游戏加分奖励机制,

方块的移动方式,按键的映射,按钮与槽的链接,计时模块等核心

内容进行编程实现。截图如图3-1。后面将对各部分详细说明。

- 8 -

图3-1 Tetrix工程

3.2 tetrixboard.h 头文件

tetrixboard.h 头文件主要是声明了各个按钮,显示窗口的实现

方法,以及窗体尺寸,头文件只起到声明的作用,具体的实例化在

函数中实现。

//! [0]

class TetrixBoard : public QFrame

{

Q_OBJECT

public:

TetrixBoard(QWidget *parent = 0);

void setNextPieceLabel(QLabel *label); //声明下一个方块

预览显

- 9 -

//示方法

QSize sizeHint() const;

QSize minimumSizeHint() const; //尺寸

public slots: //槽函数

void start(); //开始按钮实现方法

void pause(); //暂停按钮实现,返回值void型

signals:

void scoreChanged(int score); //定义加分函数

void levelChanged(int level); //过关函数

void linesRemovedChanged(int numLines); //消除显示函数实

protected:

void paintEvent(QPaintEvent *event); //paintevent画图事件

void keyPressEvent(QKeyEvent *event);

void timerEvent(QTimerEvent *event); //计时模块实现

//! [0]

3.3 tetrixpiece.h

Tetrixpiece.h声明定义方块形状的实现,通过坐标来控制,同样

这里也只是声明,具体实现不在此处。

public:

TetrixPiece() { setShape(NoShape); }

- 10 -

void setRandomShape();

void setShape(TetrixShape shape); //产生图形

TetrixShape shape() const { return pieceShape; }

int x(int index) const { return coords[index][0]; }

int y(int index) const { return coords[index][1]; }

int minX() const; //x最小值

int maxX() const; //x最大值

int minY() const; //y最小值

int maxY() const; //y最大值

TetrixPiece rotatedLeft() const; //左旋转

TetrixPiece rotatedRight() const; //右旋转

private:

void setX(int index, int x) { coords[index][0] = x; } //x

坐标

void setY(int index, int y) { coords[index][1] = y; } //y

坐标

TetrixShape pieceShape;

int coords[4][2];

3.4 tetrixwindow.h

Tetrixwindow.h部分是声明按钮与显示框,只是把图形界面声

明出来,与前面Tetrixboard声明的实现方法有所区别,两部分配合才

- 11 -

能实现完整的功能。

//! [0]

class TetrixWindow : public QWidget

{

Q_OBJECT

public:

TetrixWindow();

private:

QLabel *createLabel(const QString &text);

TetrixBoard *board;

QLabel *nextPieceLabel; //下一个方块显示框

QLCDNumber *scoreLcd; //分数显示框

QLCDNumber *levelLcd; //关卡显示框

QLCDNumber *linesLcd; //消除行数显示框

QPushButton *startButton; //开始按钮

QPushButton *quitButton; //退出按钮

QPushButton *pauseButton; //暂停按钮

};

//! [0]

3.5

Main函数是C,C++,Qt程序的入口,main函数代码少,起引

- 12 -

导作用,也包括程序的出口。

int main(int argc, char *argv[]) //C++入口

{

QApplication app(argc, argv); //Qt入口

TetrixWindow window;

();

qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));

return (); //C++于Qt出口

}

3.6

对应头文件tetrixpiece.h主要实例化方

块形状的产生,这里已数组控制七种方块形状。

//! [1]方块形状控制

void TetrixPiece::setShape(TetrixShape shape)

{

static const int coordsTable[8][4][2] = {

{ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },

{ { 0, -1 }, { 0, 0 }, { -1, 0 }, { -1, 1 } },

{ { 0, -1 }, { 0, 0 }, { 1, 0 }, { 1, 1 } },

{ { 0, -1 }, { 0, 0 }, { 0, 1 }, { 0, 2 } },

{ { -1, 0 }, { 0, 0 }, { 1, 0 }, { 0, 1 } },

- 13 -

{ { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } },

{ { -1, -1 }, { 0, -1 }, { 0, 0 }, { 0, 1 } },

{ { 1, -1 }, { 0, -1 }, { 0, 0 }, { 0, 1 } }

}; //次数组有八个成员,因为虽然只有七种图形,但

//是一字型竖起来又是一种新的图形

for (int i = 0; i < 4 ; i++) {

for (int j = 0; j < 2; ++j)

coords[i][j] = coordsTable[shape][i][j];

}

pieceShape = shape;

//! [1] //! [2] 图形随机产生并出现在活动区域

}

//! [2]

3.7

是对tetrixwindow.h头文件的实例化,包括三个

功能按钮,五个显示部分,信号与槽的链接等。

3.7.1 显示框

nextPieceLabel = new QLabel;

nextPieceLabel->setFrameStyle(QFrame::Box |

- 14 -

QFrame::Raised);

nextPieceLabel->setAlignment(Qt::AlignCenter);

board->setNextPieceLabel(nextPieceLabel);

//下一个将出现的图形预览

//! [1]

scoreLcd = new QLCDNumber(5);

scoreLcd->setSegmentStyle(QLCDNumber::Filled);

//! [1] 分数显示区域

levelLcd = new QLCDNumber(2);

levelLcd->setSegmentStyle(QLCDNumber::Filled);

//关卡显示

linesLcd = new QLCDNumber(5);

linesLcd->setSegmentStyle(QLCDNumber::Filled);

//消除行数显示

3.7.2 功能按钮

//! [2]

startButton = new QPushButton(tr("&Start"));

startButton->setFocusPolicy(Qt::NoFocus);

quitButton = new QPushButton(tr("&Quit"));

quitButton->setFocusPolicy(Qt::NoFocus);

pauseButton = new QPushButton(tr("&Pause"));

- 15 -

//! [2] //! [3]

pauseButton->setFocusPolicy(Qt::NoFocus);

//! [3] //! [4]三个按钮的功能及实现机制

3.7.3 信号与槽

connect(startButton, SIGNAL(clicked()), board,

SLOT(start()));

//! [4] //! [5]

connect(quitButton , SIGNAL(clicked()), qApp,

SLOT(quit()));

connect(pauseButton, SIGNAL(clicked()), board,

SLOT(pause()));

1. connect(board, SIGNAL(scoreChanged(int)), scoreLcd,

SLOT(display(int)));

connect(board, SIGNAL(levelChanged(int)), levelLcd,

SLOT(display(int)));

connect(board, SIGNAL(linesRemovedChanged(int)),

linesLcd, SLOT(display(int)));

//! [5]信号与槽的链接,按键产生的信号与槽相连接

3.7.4 游戏面板布局

//! [6]

- 16 -

QGridLayout *layout = new QGridLayout;

layout->addWidget(createLabel(tr("NEXT")), 0, 0);

layout->addWidget(nextPieceLabel, 1, 0);

layout->addWidget(createLabel(tr("LEVEL")), 2, 0);

layout->addWidget(levelLcd, 3, 0);

layout->addWidget(startButton, 4, 0);//左边部分的内容

layout->addWidget(board, 0, 1, 6, 1);

layout->addWidget(createLabel(tr("SCORE")), 0, 2);

layout->addWidget(scoreLcd, 1, 2);

layout->addWidget(createLabel(tr("LINES REMOVED")), 2, 2);

layout->addWidget(linesLcd, 3, 2);

layout->addWidget(quitButton, 4, 2);

layout->addWidget(pauseButton, 5, 2);

setLayout(layout); //右半部分

setWindowTitle(tr("Tetrix")); //顶部显示

resize(550, 370); //初始大小

此部分实现功能多,代码量大,是本设计游戏功能实现的核心,这

里将其拆分成几个小模块来解释说明。

- 17 -

3.8.1游戏初始化,复位的实现

//! [0]

TetrixBoard::TetrixBoard(QWidget *parent)

: QFrame(parent)

{

setFrameStyle(QFrame::Panel | QFrame::Sunken); //面

板,方块活动界面

setFocusPolicy(Qt::StrongFocus); //设置焦点

isStarted = false; //赋初值

isPaused = false; //赋初值

clearBoard(); //游戏开始前清空底板

domShape(); //下一个显示,随机显示图

}

//! [0]随机产生方块形状

//! [1]默认尺寸

void TetrixBoard::setNextPieceLabel(QLabel *label)

{

nextPieceLabel = label; //实例化出来下一个方块显示

}

//! [1]

//! [2]

- 18 -

QSize TetrixBoard::sizeHint() const

{

return QSize(BoardWidth * 15,

BoardHeight * 15);

} //面板默认尺寸

QSize TetrixBoard::minimumSizeHint() const

//! [2] //! [3]最小尺寸

{

return QSize(BoardWidth * 5,

BoardHeight * 5);

}

//! [3]

/! [4]初始化

3.8.2 游戏开始与暂停

//! [4]游戏开始

void TetrixBoard::start()

{

if (isPaused) //判断是否处于暂停状态

return;

isStarted = true; //游戏开始“Start”为真

isWaitingAfterLine = false; //

- 19 -

numLinesRemoved = 0; //刚开始游戏没有消除行,所以为0

numPiecesDropped = 0;

score = 0; //开始前分数为零,游戏开始,分数开始改变

level = 1; //开始时关卡为1

clearBoard();

emit linesRemovedChanged(numLinesRemoved);

emit scoreChanged(score);

emit levelChanged(level); //各部分功能激活,开始工

newPiece();

(timeoutTime(), this); //记时器开始计时

}

//! [4]

//! [5]暂停功能

void TetrixBoard::pause()

{

if (!isStarted) //判断游戏是否已经开始

return;

isPaused = !isPaused;

if (isPaused) {

(); //如果处于暂停状态,停止计时

} else {

- 20 -

(timeoutTime(), this);

}

update();

//! [5] //! [6]

}

//! [6]

//! [7]

void TetrixBoard::paintEvent(QPaintEvent *event)

{

QFrame::paintEvent(event); //绘图事件

QPainter painter(this);

QRect rect = contentsRect();

//! [7]

if (isPaused) {

xt(rect, Qt::AlignCenter,

tr("*zzia^briup*")); // 暂停时方块活动窗口显示内容,当然可以

改为其它,比如“Pause”。

return;

}

- 21 -

3.8.3 按键控制游戏

//! [14]按键控制板块

switch (event->key()) {

case Qt::Key_Left:

tryMove(curPiece, curX - 1, curY);

break; //左键控制方块左移,x坐标减小,y不变

case Qt::Key_Right:

tryMove(curPiece, curX + 1, curY);

break; //右键控制方块右移,x坐标增加,y不变

case Qt::Key_Down:

tryMove(dRight(), curX, curY);

break; //下键控制方块向右旋转

case Qt::Key_Up:

tryMove(dLeft(), curX, curY);

break; //上键控制方块想做旋转

case Qt::Key_Space:

dropDown();

break; //空格键控制方块直接下降到底部

case Qt::Key_D:

oneLineDown();

break; //D键控制下降加速

default:

- 22 -

QFrame::keyPressEvent(event);//按钮触发事件

}

//! [14]

}

3.8.4计时模块

//! [15]计时模块

void TetrixBoard::timerEvent(QTimerEvent *event)

{

if (event->timerId() == d()) {

if (isWaitingAfterLine) {

isWaitingAfterLine = false;

newPiece();

(timeoutTime(), this);//新开时游戏,

计时开始

} else {

oneLineDown();

}

} else {

QFrame::timerEvent(event);

//! [15] //! [16]

}

- 23 -

//! [16] //! [17]

}

//! [17] 这里用到多充判断,因为多种情况都涉及到计时的开始

于暂停

3.8.5 方块的活动

在方块活动区域,通过按键对方块的活动进行控制,方块本身就

有下降的功能,这里方块的坐标随时都在改变。

//! [18]方块活动区域初始状态没有图形

void TetrixBoard::clearBoard()

{

for (int i = 0; i < BoardHeight * BoardWidth; ++i)

board[i] = NoShape; //初始,没有方块

}

//! [18]

//! [19]方块下降

void TetrixBoard::dropDown()

{

int dropHeight = 0;

int newY = curY; //开始出现方块时坐标

while (newY > 0) {

if (!tryMove(curPiece, curX, newY - 1))

- 24 -

break;

--newY; //不断下降,y坐标跟着减小

++dropHeight; //而下降的高度增加

}

pieceDropped(dropHeight);

//! [19] //! [20]

}

//! [20]

//! [21]

void TetrixBoard::oneLineDown()

{

if (!tryMove(curPiece, curX, curY - 1))

pieceDropped(0); //没有左右移动时,只有y坐标变化

}

//! [21]

3.8.6 过关与奖励

本游戏每出现25个方块关卡加一,采用多种奖励加分机制。

//! [22]下降25个方块等级加一

void TetrixBoard::pieceDropped(int dropHeight)

{

- 25 -

for (int i = 0; i < 4; ++i) {

int x = curX + curPiece.x(i);

int y = curY - curPiece.y(i);

shapeAt(x, y) = ();

}

++numPiecesDropped;

if (numPiecesDropped % 25 == 0) {

++level; //出现25个方块,关卡加一

(timeoutTime(), this); //计时

emit levelChanged(level); //关卡控制

}

score += dropHeight + 7; //奖励机制,快速下降加分

emit scoreChanged(score); //分数变化

removeFullLines();

if (!isWaitingAfterLine)

newPiece();

//! [22] //! [23]

}

//! [23]

//! [24]

void TetrixBoard::removeFullLines() //消除

{

- 26 -

int numFullLines = 0;

for (int i = BoardHeight - 1; i >= 0; --i) {

bool lineIsFull = true; //此行已满,返回真

for (int j = 0; j < BoardWidth; ++j) {

if (shapeAt(j, i) == NoShape) {

lineIsFull = false; //不满,有空隙

break;

}

}

if (lineIsFull) {

//! [24] //! [25]

++numFullLines; //满了就消除一行,显示加一

for (int k = i; k < BoardHeight - 1; ++k) {

for (int j = 0; j < BoardWidth; ++j)

shapeAt(j, k) = shapeAt(j, k + 1);

}

//! [25] //! [26]

for (int j = 0; j < BoardWidth; ++j)

shapeAt(j, BoardHeight - 1) = NoShape;

}

//! [26] //! [27]

}

- 27 -

//! [27]

//! [28]

if (numFullLines > 0) {

numLinesRemoved += numFullLines; //消除行数显示

score += 10 * numFullLines;//消除一行再次奖励10分

emit linesRemovedChanged(numLinesRemoved);

emit scoreChanged(score); //分数改变

(500, this); //初始速度,这里以下降间

隔时间来//表示,默认第一关500ms

isWaitingAfterLine = true;

pe(NoShape);

update();

}

//! [28] //! [29]

}

//! [29]

3.8.7 方块颜色控制

随机产生不同的颜色,这里也由数组控制,列出几种颜色。

//! [36]方块颜色(随机产生)

void TetrixBoard::drawSquare(QPainter &painter, int x, int

y, TetrixShape shape)

- 28 -

{

static const QRgb colorTable[8] = {

0x000000, 0xCC6666, 0x66CC66, 0x6666CC,

0xCD2626, 0xCC66CC, 0x66CCCC, 0xDAAA00

}; //颜色代码块,各种颜色随机出现

QColor color = colorTable[int(shape)];

ct(x + 1, y + 1, squareWidth() - 2,

squareHeight() - 2,

color);

(()); //产生亮色

ne(x, y + squareHeight() - 1, x, y);

ne(x, y, x + squareWidth() - 1, y);

(()); //暗色

ne(x + 1, y + squareHeight() - 1,

x + squareWidth() - 1, y + squareHeight()

- 1);

ne(x + squareWidth() - 1, y + squareHeight()

- 1,

x + squareWidth() - 1, y + 1);

}

//! [36]

- 29 -

总结

游戏代码的分析到此结束,通过本设计,我熟练掌握了QT中图形

界面的实现,信号与槽的链接,对C与C++时学过的数组,循环,指针,

条件判断等有了进一步的理解,运用更灵活,增强了动手动脑能力,对

编程有了新的认识,对所学知识确实起到了复习巩固的作用。

*****

致谢

大学四年的学习以今天的毕业论文画了一个句号。感谢大学四年,

各位老师对我的教诲,感谢郑州航空工业管理学院对我的栽培,感谢杰

普科技有限公司于文思创新集团给我培训实习的机会,感谢大家有缘能

在生命中重要的四年,出现在彼此的生活中,大学四年学到的文化知识,

做人道理将使我受益终生,感谢系部各位领导的关怀,张辅导员提倡的

读书活动让我们获益匪浅,我很荣幸在大学期间有这样一个辅导员,他

使我们人生的导师。在这里还要特别感谢华红艳主任,王义琴,刘涛,

晋剑老师对本次毕业设计的指导支持。最后希望各位领导、各位老师工

作顺利,身体健康,所有关心支持我的同学、朋友都有一个美好的前程。

参考文献

【1】谭浩强,张基温,C语言程序设计教程(第3版)[M].高等教育出版社,1991年08月

- 30 -

2024年3月26日发(作者:承古)

内 容 摘 要

俄罗斯方块是个比较经典的小游戏,它实现由四块正方形的色块

组成,然后存储在一个数组的四个元素中,计算机随机产生不同七种类

型的方块,根据计算机定时器控制它在一定的时间不停的产生,用户根

据键盘的四个方向键控制翻转、向左、向右和向下操作,(用信号和槽

函数的关联来实现对按键事件的控制)。然后程序根据这七种方块堆叠

成各种不同的模型。本设计大体分以下三部分:

第一部分是简介,用基本方法实现自己的俄罗斯方块游戏,介绍

游戏的基本概况及要实现的功能。第二部分是功能演示,验证游戏可否

按预想方案运行,验证运行流畅度,图形界面的美观度。第三部分是代

码分析,这里将展示整个游戏编程代码及接口函数。

本次设计用到的工具是基于UBUNTU下的QT软件,图行界面的处

理都是代码实现。

关 键 词

数组;定时器;信号;槽函数;QT

I

Design and implementation of Tetris, based on the QT

Name:Yiwenbo Teacher:Wangyiqin

Abstract

Tetris is a classic game, it consists of four square blocks of color, and

then stored in an array of four elements, the computer randomly generated

box of the seven types, according to the computer timer control it stop to

produce a certain amount of time, according to the four directions of the

keyboard keys to control flip, left, right and down operation (signal and slot

functions associated with control of key events). The program then based on

these seven box stacked into a variety of different models. This design is

generally divided into the following three parts: The first part is the

introduction to the basic methods to achieve their own game of Tetris. The

second part is the functional demonstration; verify that the game please run

the desired program. The third part is the game analysis, will show the entire

game programming code and an excuse to function. The design tool used is

based on the QT under UBUNTU software, the graph line interface

processing is code to achieve.

Key words

array; cell function; timer; signal;Qt

II

目 录

引言 ................................................... - 1 -

第一部分 简介 .......................................... - 3 -

1.1游戏功能 ......................................... - 3 -

1.2 游戏界面与控制 .................................. - 3 -

1.2.1游戏窗口 .................................... - 3 -

1.2.2方块形状 .................................... - 4 -

1.2.3键盘处理事件 ................................ - 4 -

1.2.4显示需求 .................................... - 4 -

第二部分 功能展示 ...................................... - 5 -

2.1 打开游戏 ........................................... - 5 -

2.2 进入游戏 ........................................ - 6 -

2.3游戏过关 ......................................... - 6 -

2.4 游戏暂停 ........................................ - 7 -

2.5 游戏退出 ........................................ - 8 -

第三部分 代码分析 ...................................... - 8 -

3.1 Tetrix工程 .................................... - 8 -

3.2 tetrixboard.h ................................. - 9 -

3.3 tetrixpiece.h ................................. - 10 -

3.4 tetrixwindow.h ................................ - 11 -

3.5 ...................................... - 12 -

III

3.6 ............................... - 13 -

3.7 ............................... - 14 -

3.7.1 显示框 .................................... - 14 -

3.7.2 功能按钮 .................................. - 15 -

3.7.3 信号与槽 .................................. - 16 -

3.7.4 游戏面板布局 .............................. - 16 -

.................................. - 17 -

3.8.1游戏初始化,复位的实现 ..................... - 18 -

3.8.2 游戏开始与暂停 ............................ - 19 -

3.8.3 按键控制游戏 .............................. - 22 -

3.8.4计时模块 ................................... - 23 -

3.8.5 方块的活动 ................................ - 24 -

3.8.6 过关与奖励 ................................ - 25 -

3.8.7 方块颜色控制 .............................. - 28 -

总结 .................................................. - 30 -

致谢 .................................................. - 30 -

参考文献 .............................................. - 30 -

IV

基于QT 的俄罗斯方块的设计与实现

081308233 易文波 指导教师:王义琴 讲师

引言

Qt是一个1991年由奇趣科技开发的跨平台C++图形用户界面应用程

序开发框架。它既可以开发GUI程式,也可用于开发非GUI程式,比如

控制台工具和服务器。Qt是面向对象语言,易于扩展,并且允许组件编

程。2008年,奇趣科技被诺基亚公司收购,QT也因此成为诺基亚旗下的

编程语言工具。

Qt支持下述平台:MS/Windows - 95、98、NT 4.0、ME、2000、XP 、

Vista和Win7 Unix/X11 - Linux、Sun Splaris、HP-UX、CompapTru64

UNIX、IBM AIX、SGI IRIX、FreeBSD、BSD/OS和其它很多X11平台

Macintosh - Mac OS X Embedded - 有帧缓冲(framebuffer)支持的嵌

入式Linux平台,Windows CE。

Qt具有以下优势:

面向对像,Qt 的良好封装机制使得Qt的模块化程度非常高,可重

用性较好,对于用户开发来说是非常方便的。 Qt 提供了一种称为

signals/slots的安全类型来替代callback,这使得各个元件之间的协

同工作变得十分简单。

丰富API,Qt包括多达250个以上的 C++ 类,还提供基于模板的

collections, serialization, file, I/O device, directory

- 1 -

management, date/time 类。甚至还包括正则表达式(在计算机科学

中,是指一个用来描述或者匹配一系列符合某个句法规则的字符串的单

个字符串。)的处理 功能。支持 2D/3D 图形渲染,支持OpenGL大量的

开发文档XML 支持Webkit 引擎的集成,可以实现本地界面与Web内容

的无缝集成。

俄罗斯方块是一款风靡全球的电视游戏机和掌上游戏机游戏,它曾

经造成的轰动与造成的经济价值可以说是游戏史上的一件大事。俄罗斯

方块游戏可以说是随计算机的发展而发展,并不断推陈出新演变出各种

类似游戏, 深受广大玩家喜爱。这个游戏有的简单, 有的复杂, 但其根

本原理是一样的都是对运动的方块进行组合, 来训练玩家的反应能力。

俄罗斯方块最早还是出现在PC机上,而我国的用户都是通过红白

机了解、喜欢上它的。现在QQ等游戏平台又将重新掀起这股让人沉迷

的俄罗斯方块风潮。对一般用户来说,它的规则简单,容易上手,且游

戏过程变化无穷,而在游戏平台上的对战模式更增加了它的娱乐性和挑

战性,使用户既能感受到游戏中的乐趣,也给用户提供了一个展现自己

高超技艺的场所。

本设计利用数组作为方块的数据结构,提出一种用C语言和C++来

实现的方法,实现基本的方块游戏功能,虽然不能实现联网对战功能,

但是可以通过设计实现本游戏巩固所学知识,增强动手能力,了解并熟

悉游戏软件的设计与开发过程。

本设计基于Qt,实现基本的方块游戏,所有图形界面均由代码实

现。通过验证各图形界面良好实现,游戏流畅运行。

- 2 -

第一部分 简介

1.1游戏功能

随机产生不同的形状(长条形、Z字形、反Z形、田字形、7字形、

反7形、T字型)下落填充给定的区域,若填满一行便消掉,相应区域

计数,此时分数有奖励,每消一行奖励十分,当方块出现一定的个数时,

过关,设置多个关卡,每关方块下落的速度不同,第一关默认下降速度

500ms(0.5s),以后每过一关速度递加,增加游戏难度。每出现一个方

块图形分数加七,如果使用快速下降功能(游戏中点击空格键)会有加

分,具体实现后面有详细介绍,若在游戏中各形状填满了给定区域,游

戏失败处于定格状态,此时可以重新开始游戏。游戏有暂停功能,当玩

家点暂停按钮时,游戏暂停,再次点击暂停按钮,游戏继续。

1.2 游戏界面与控制

1.2.1游戏窗口

良好的用户界面,有关数,分数,下一个方块预览,消除行数显示。

让方块在一定的区域内运动和变形,该区域用一种颜色表明,既用一种

颜色作为背景,这里为白色,而且该区域(游戏显示窗体)下陷,有层

次感,方块颜色随机,避免游戏单调。

- 3 -

1.2.2方块形状

良好的方块形状设计,方块简洁大方,大小适中,绘制七种常见的

基本图形(长条形、Z字形、反Z形、田字形、7字形、反7形、T字型),

各个方块要能实现它的变形,可设为顺时针或逆时针变形,本设计实现

了顺时针与逆时针两种旋转方式。七种方块随机产生示意图如图1-1。

随机产生一个数

随机数

反Z形

一字形

Z字形

7字形

反7形

倒T形

田字型

图1-1随机产生方块

1.2.3键盘处理事件

方块下落时,可通过键盘方向键(上、下、左、右、)空格键,D键

对该方块进行向上(顺时针变形),向下(逆时针变形)、向左、向右移动,

空格(直接降到底部),D(加快下降速度)。游戏面板上设置“Start”,

“Pause”,“Quite”三个按钮,分别用来控制游戏开始,暂停,退出功

能。

1.2.4显示需求

当不同的方块填满一行时可以消行,剩余方块向下移动并统计分

数。当方块下降一定的个数时过关。设置多个关卡,每关方块下落的速

- 4 -

度不同。游戏能在特定区域实时显示当前关卡,分数,消除行数,下一

个将要出现的图形。

第二部分 功能展示

本部分就方块游戏的功能配合截图进行检测与展示。

2.1 进入游戏

打开游戏,此时显示游戏的主窗口(由于Qt编程的可移植性,游

戏的窗口样式与当前平台或主题配色及样式保持一致),其中包括:

“Start”,“Quit”,“Pause”三个按钮,以及“NEXT”,“LEVEL”,“SCORE”,

“LINES REMOVED”四个显示框。中间空白长方形区域为方块活动区。

此时游戏处于初始化状态,各个显示卡内容均为0或空白,方块活动区

还没有出现方块。游戏状态截图如图2-1。

图2-1进入游戏

- 5 -

2.2 开始游戏

点击“Start”按钮,游戏开始,中间方块活动区域有方块出现并

下落,“LEVEL”由0变为1,“SCORE”也发生改变,截图中出现了两个

图形,所以分数显示为14,“NEXT”显示下一个将要出现的方块形状,

而由于还没有消除一行“LINES REMOVED”依然显示0,此时可通过键盘

控制游戏。如图2-2。

图2-2开始游戏

2.3游戏过关

当游戏中出现方块图形数达到25个时过关,此时“LEVEL”自动

变为2,方块下降速度加快,截图中显示内容可知,已经消除了十一行,

分数是702分,下一个将要出现的方块是7字形,同时由图可以看出方

块的形状颜色都是随机产生的。如图2-3。

- 6 -

图2-3游戏过关

2.4 游戏暂停

玩家中途暂停游戏时可以点击“Pause”,游戏会处于暂停状态,各

个显示窗口暂停计数,方块活动区域显示><,此时操作键盘游戏

将不会响应,当再次点击“Pause”按钮时游戏继续,如图2-4。

图2-4暂停游戏

- 7 -

2.5 游戏退出

游戏退出有两种情况,一种是方块堆满活动区且无法消除,游戏结

束,另一种情况是玩家中途退出,可以点击“Quit”按钮,或者直接关

闭装口,游戏退出再次开始时数据丢失,因为游戏会自动初始化。

通过检测,此俄罗斯方块游戏运行正常,各部分功能按照预期良好

实现,下面将具体分析各部分功能对应的代码、函数、信号、槽等。

第三部分 代码分析

3.1 Tetrix工程

每个程序都有一个工程,此工程下包含各种头文件以及对应的

函数,本工程包含的头文件有:tetrixboard.h,tetrixpiece.h,

tetrixwindow.h,三个函数,,

,后面将对各头文件及函数具体分析。由于游戏

代码量大,时间仓促,而且刚学QT,运用不是很熟练,本设计在老

师的指导下完成,有部分代码框架是老师代为实现,本人主要对

部分,包括游戏各功能的实现,游戏加分奖励机制,

方块的移动方式,按键的映射,按钮与槽的链接,计时模块等核心

内容进行编程实现。截图如图3-1。后面将对各部分详细说明。

- 8 -

图3-1 Tetrix工程

3.2 tetrixboard.h 头文件

tetrixboard.h 头文件主要是声明了各个按钮,显示窗口的实现

方法,以及窗体尺寸,头文件只起到声明的作用,具体的实例化在

函数中实现。

//! [0]

class TetrixBoard : public QFrame

{

Q_OBJECT

public:

TetrixBoard(QWidget *parent = 0);

void setNextPieceLabel(QLabel *label); //声明下一个方块

预览显

- 9 -

//示方法

QSize sizeHint() const;

QSize minimumSizeHint() const; //尺寸

public slots: //槽函数

void start(); //开始按钮实现方法

void pause(); //暂停按钮实现,返回值void型

signals:

void scoreChanged(int score); //定义加分函数

void levelChanged(int level); //过关函数

void linesRemovedChanged(int numLines); //消除显示函数实

protected:

void paintEvent(QPaintEvent *event); //paintevent画图事件

void keyPressEvent(QKeyEvent *event);

void timerEvent(QTimerEvent *event); //计时模块实现

//! [0]

3.3 tetrixpiece.h

Tetrixpiece.h声明定义方块形状的实现,通过坐标来控制,同样

这里也只是声明,具体实现不在此处。

public:

TetrixPiece() { setShape(NoShape); }

- 10 -

void setRandomShape();

void setShape(TetrixShape shape); //产生图形

TetrixShape shape() const { return pieceShape; }

int x(int index) const { return coords[index][0]; }

int y(int index) const { return coords[index][1]; }

int minX() const; //x最小值

int maxX() const; //x最大值

int minY() const; //y最小值

int maxY() const; //y最大值

TetrixPiece rotatedLeft() const; //左旋转

TetrixPiece rotatedRight() const; //右旋转

private:

void setX(int index, int x) { coords[index][0] = x; } //x

坐标

void setY(int index, int y) { coords[index][1] = y; } //y

坐标

TetrixShape pieceShape;

int coords[4][2];

3.4 tetrixwindow.h

Tetrixwindow.h部分是声明按钮与显示框,只是把图形界面声

明出来,与前面Tetrixboard声明的实现方法有所区别,两部分配合才

- 11 -

能实现完整的功能。

//! [0]

class TetrixWindow : public QWidget

{

Q_OBJECT

public:

TetrixWindow();

private:

QLabel *createLabel(const QString &text);

TetrixBoard *board;

QLabel *nextPieceLabel; //下一个方块显示框

QLCDNumber *scoreLcd; //分数显示框

QLCDNumber *levelLcd; //关卡显示框

QLCDNumber *linesLcd; //消除行数显示框

QPushButton *startButton; //开始按钮

QPushButton *quitButton; //退出按钮

QPushButton *pauseButton; //暂停按钮

};

//! [0]

3.5

Main函数是C,C++,Qt程序的入口,main函数代码少,起引

- 12 -

导作用,也包括程序的出口。

int main(int argc, char *argv[]) //C++入口

{

QApplication app(argc, argv); //Qt入口

TetrixWindow window;

();

qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));

return (); //C++于Qt出口

}

3.6

对应头文件tetrixpiece.h主要实例化方

块形状的产生,这里已数组控制七种方块形状。

//! [1]方块形状控制

void TetrixPiece::setShape(TetrixShape shape)

{

static const int coordsTable[8][4][2] = {

{ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },

{ { 0, -1 }, { 0, 0 }, { -1, 0 }, { -1, 1 } },

{ { 0, -1 }, { 0, 0 }, { 1, 0 }, { 1, 1 } },

{ { 0, -1 }, { 0, 0 }, { 0, 1 }, { 0, 2 } },

{ { -1, 0 }, { 0, 0 }, { 1, 0 }, { 0, 1 } },

- 13 -

{ { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } },

{ { -1, -1 }, { 0, -1 }, { 0, 0 }, { 0, 1 } },

{ { 1, -1 }, { 0, -1 }, { 0, 0 }, { 0, 1 } }

}; //次数组有八个成员,因为虽然只有七种图形,但

//是一字型竖起来又是一种新的图形

for (int i = 0; i < 4 ; i++) {

for (int j = 0; j < 2; ++j)

coords[i][j] = coordsTable[shape][i][j];

}

pieceShape = shape;

//! [1] //! [2] 图形随机产生并出现在活动区域

}

//! [2]

3.7

是对tetrixwindow.h头文件的实例化,包括三个

功能按钮,五个显示部分,信号与槽的链接等。

3.7.1 显示框

nextPieceLabel = new QLabel;

nextPieceLabel->setFrameStyle(QFrame::Box |

- 14 -

QFrame::Raised);

nextPieceLabel->setAlignment(Qt::AlignCenter);

board->setNextPieceLabel(nextPieceLabel);

//下一个将出现的图形预览

//! [1]

scoreLcd = new QLCDNumber(5);

scoreLcd->setSegmentStyle(QLCDNumber::Filled);

//! [1] 分数显示区域

levelLcd = new QLCDNumber(2);

levelLcd->setSegmentStyle(QLCDNumber::Filled);

//关卡显示

linesLcd = new QLCDNumber(5);

linesLcd->setSegmentStyle(QLCDNumber::Filled);

//消除行数显示

3.7.2 功能按钮

//! [2]

startButton = new QPushButton(tr("&Start"));

startButton->setFocusPolicy(Qt::NoFocus);

quitButton = new QPushButton(tr("&Quit"));

quitButton->setFocusPolicy(Qt::NoFocus);

pauseButton = new QPushButton(tr("&Pause"));

- 15 -

//! [2] //! [3]

pauseButton->setFocusPolicy(Qt::NoFocus);

//! [3] //! [4]三个按钮的功能及实现机制

3.7.3 信号与槽

connect(startButton, SIGNAL(clicked()), board,

SLOT(start()));

//! [4] //! [5]

connect(quitButton , SIGNAL(clicked()), qApp,

SLOT(quit()));

connect(pauseButton, SIGNAL(clicked()), board,

SLOT(pause()));

1. connect(board, SIGNAL(scoreChanged(int)), scoreLcd,

SLOT(display(int)));

connect(board, SIGNAL(levelChanged(int)), levelLcd,

SLOT(display(int)));

connect(board, SIGNAL(linesRemovedChanged(int)),

linesLcd, SLOT(display(int)));

//! [5]信号与槽的链接,按键产生的信号与槽相连接

3.7.4 游戏面板布局

//! [6]

- 16 -

QGridLayout *layout = new QGridLayout;

layout->addWidget(createLabel(tr("NEXT")), 0, 0);

layout->addWidget(nextPieceLabel, 1, 0);

layout->addWidget(createLabel(tr("LEVEL")), 2, 0);

layout->addWidget(levelLcd, 3, 0);

layout->addWidget(startButton, 4, 0);//左边部分的内容

layout->addWidget(board, 0, 1, 6, 1);

layout->addWidget(createLabel(tr("SCORE")), 0, 2);

layout->addWidget(scoreLcd, 1, 2);

layout->addWidget(createLabel(tr("LINES REMOVED")), 2, 2);

layout->addWidget(linesLcd, 3, 2);

layout->addWidget(quitButton, 4, 2);

layout->addWidget(pauseButton, 5, 2);

setLayout(layout); //右半部分

setWindowTitle(tr("Tetrix")); //顶部显示

resize(550, 370); //初始大小

此部分实现功能多,代码量大,是本设计游戏功能实现的核心,这

里将其拆分成几个小模块来解释说明。

- 17 -

3.8.1游戏初始化,复位的实现

//! [0]

TetrixBoard::TetrixBoard(QWidget *parent)

: QFrame(parent)

{

setFrameStyle(QFrame::Panel | QFrame::Sunken); //面

板,方块活动界面

setFocusPolicy(Qt::StrongFocus); //设置焦点

isStarted = false; //赋初值

isPaused = false; //赋初值

clearBoard(); //游戏开始前清空底板

domShape(); //下一个显示,随机显示图

}

//! [0]随机产生方块形状

//! [1]默认尺寸

void TetrixBoard::setNextPieceLabel(QLabel *label)

{

nextPieceLabel = label; //实例化出来下一个方块显示

}

//! [1]

//! [2]

- 18 -

QSize TetrixBoard::sizeHint() const

{

return QSize(BoardWidth * 15,

BoardHeight * 15);

} //面板默认尺寸

QSize TetrixBoard::minimumSizeHint() const

//! [2] //! [3]最小尺寸

{

return QSize(BoardWidth * 5,

BoardHeight * 5);

}

//! [3]

/! [4]初始化

3.8.2 游戏开始与暂停

//! [4]游戏开始

void TetrixBoard::start()

{

if (isPaused) //判断是否处于暂停状态

return;

isStarted = true; //游戏开始“Start”为真

isWaitingAfterLine = false; //

- 19 -

numLinesRemoved = 0; //刚开始游戏没有消除行,所以为0

numPiecesDropped = 0;

score = 0; //开始前分数为零,游戏开始,分数开始改变

level = 1; //开始时关卡为1

clearBoard();

emit linesRemovedChanged(numLinesRemoved);

emit scoreChanged(score);

emit levelChanged(level); //各部分功能激活,开始工

newPiece();

(timeoutTime(), this); //记时器开始计时

}

//! [4]

//! [5]暂停功能

void TetrixBoard::pause()

{

if (!isStarted) //判断游戏是否已经开始

return;

isPaused = !isPaused;

if (isPaused) {

(); //如果处于暂停状态,停止计时

} else {

- 20 -

(timeoutTime(), this);

}

update();

//! [5] //! [6]

}

//! [6]

//! [7]

void TetrixBoard::paintEvent(QPaintEvent *event)

{

QFrame::paintEvent(event); //绘图事件

QPainter painter(this);

QRect rect = contentsRect();

//! [7]

if (isPaused) {

xt(rect, Qt::AlignCenter,

tr("*zzia^briup*")); // 暂停时方块活动窗口显示内容,当然可以

改为其它,比如“Pause”。

return;

}

- 21 -

3.8.3 按键控制游戏

//! [14]按键控制板块

switch (event->key()) {

case Qt::Key_Left:

tryMove(curPiece, curX - 1, curY);

break; //左键控制方块左移,x坐标减小,y不变

case Qt::Key_Right:

tryMove(curPiece, curX + 1, curY);

break; //右键控制方块右移,x坐标增加,y不变

case Qt::Key_Down:

tryMove(dRight(), curX, curY);

break; //下键控制方块向右旋转

case Qt::Key_Up:

tryMove(dLeft(), curX, curY);

break; //上键控制方块想做旋转

case Qt::Key_Space:

dropDown();

break; //空格键控制方块直接下降到底部

case Qt::Key_D:

oneLineDown();

break; //D键控制下降加速

default:

- 22 -

QFrame::keyPressEvent(event);//按钮触发事件

}

//! [14]

}

3.8.4计时模块

//! [15]计时模块

void TetrixBoard::timerEvent(QTimerEvent *event)

{

if (event->timerId() == d()) {

if (isWaitingAfterLine) {

isWaitingAfterLine = false;

newPiece();

(timeoutTime(), this);//新开时游戏,

计时开始

} else {

oneLineDown();

}

} else {

QFrame::timerEvent(event);

//! [15] //! [16]

}

- 23 -

//! [16] //! [17]

}

//! [17] 这里用到多充判断,因为多种情况都涉及到计时的开始

于暂停

3.8.5 方块的活动

在方块活动区域,通过按键对方块的活动进行控制,方块本身就

有下降的功能,这里方块的坐标随时都在改变。

//! [18]方块活动区域初始状态没有图形

void TetrixBoard::clearBoard()

{

for (int i = 0; i < BoardHeight * BoardWidth; ++i)

board[i] = NoShape; //初始,没有方块

}

//! [18]

//! [19]方块下降

void TetrixBoard::dropDown()

{

int dropHeight = 0;

int newY = curY; //开始出现方块时坐标

while (newY > 0) {

if (!tryMove(curPiece, curX, newY - 1))

- 24 -

break;

--newY; //不断下降,y坐标跟着减小

++dropHeight; //而下降的高度增加

}

pieceDropped(dropHeight);

//! [19] //! [20]

}

//! [20]

//! [21]

void TetrixBoard::oneLineDown()

{

if (!tryMove(curPiece, curX, curY - 1))

pieceDropped(0); //没有左右移动时,只有y坐标变化

}

//! [21]

3.8.6 过关与奖励

本游戏每出现25个方块关卡加一,采用多种奖励加分机制。

//! [22]下降25个方块等级加一

void TetrixBoard::pieceDropped(int dropHeight)

{

- 25 -

for (int i = 0; i < 4; ++i) {

int x = curX + curPiece.x(i);

int y = curY - curPiece.y(i);

shapeAt(x, y) = ();

}

++numPiecesDropped;

if (numPiecesDropped % 25 == 0) {

++level; //出现25个方块,关卡加一

(timeoutTime(), this); //计时

emit levelChanged(level); //关卡控制

}

score += dropHeight + 7; //奖励机制,快速下降加分

emit scoreChanged(score); //分数变化

removeFullLines();

if (!isWaitingAfterLine)

newPiece();

//! [22] //! [23]

}

//! [23]

//! [24]

void TetrixBoard::removeFullLines() //消除

{

- 26 -

int numFullLines = 0;

for (int i = BoardHeight - 1; i >= 0; --i) {

bool lineIsFull = true; //此行已满,返回真

for (int j = 0; j < BoardWidth; ++j) {

if (shapeAt(j, i) == NoShape) {

lineIsFull = false; //不满,有空隙

break;

}

}

if (lineIsFull) {

//! [24] //! [25]

++numFullLines; //满了就消除一行,显示加一

for (int k = i; k < BoardHeight - 1; ++k) {

for (int j = 0; j < BoardWidth; ++j)

shapeAt(j, k) = shapeAt(j, k + 1);

}

//! [25] //! [26]

for (int j = 0; j < BoardWidth; ++j)

shapeAt(j, BoardHeight - 1) = NoShape;

}

//! [26] //! [27]

}

- 27 -

//! [27]

//! [28]

if (numFullLines > 0) {

numLinesRemoved += numFullLines; //消除行数显示

score += 10 * numFullLines;//消除一行再次奖励10分

emit linesRemovedChanged(numLinesRemoved);

emit scoreChanged(score); //分数改变

(500, this); //初始速度,这里以下降间

隔时间来//表示,默认第一关500ms

isWaitingAfterLine = true;

pe(NoShape);

update();

}

//! [28] //! [29]

}

//! [29]

3.8.7 方块颜色控制

随机产生不同的颜色,这里也由数组控制,列出几种颜色。

//! [36]方块颜色(随机产生)

void TetrixBoard::drawSquare(QPainter &painter, int x, int

y, TetrixShape shape)

- 28 -

{

static const QRgb colorTable[8] = {

0x000000, 0xCC6666, 0x66CC66, 0x6666CC,

0xCD2626, 0xCC66CC, 0x66CCCC, 0xDAAA00

}; //颜色代码块,各种颜色随机出现

QColor color = colorTable[int(shape)];

ct(x + 1, y + 1, squareWidth() - 2,

squareHeight() - 2,

color);

(()); //产生亮色

ne(x, y + squareHeight() - 1, x, y);

ne(x, y, x + squareWidth() - 1, y);

(()); //暗色

ne(x + 1, y + squareHeight() - 1,

x + squareWidth() - 1, y + squareHeight()

- 1);

ne(x + squareWidth() - 1, y + squareHeight()

- 1,

x + squareWidth() - 1, y + 1);

}

//! [36]

- 29 -

总结

游戏代码的分析到此结束,通过本设计,我熟练掌握了QT中图形

界面的实现,信号与槽的链接,对C与C++时学过的数组,循环,指针,

条件判断等有了进一步的理解,运用更灵活,增强了动手动脑能力,对

编程有了新的认识,对所学知识确实起到了复习巩固的作用。

*****

致谢

大学四年的学习以今天的毕业论文画了一个句号。感谢大学四年,

各位老师对我的教诲,感谢郑州航空工业管理学院对我的栽培,感谢杰

普科技有限公司于文思创新集团给我培训实习的机会,感谢大家有缘能

在生命中重要的四年,出现在彼此的生活中,大学四年学到的文化知识,

做人道理将使我受益终生,感谢系部各位领导的关怀,张辅导员提倡的

读书活动让我们获益匪浅,我很荣幸在大学期间有这样一个辅导员,他

使我们人生的导师。在这里还要特别感谢华红艳主任,王义琴,刘涛,

晋剑老师对本次毕业设计的指导支持。最后希望各位领导、各位老师工

作顺利,身体健康,所有关心支持我的同学、朋友都有一个美好的前程。

参考文献

【1】谭浩强,张基温,C语言程序设计教程(第3版)[M].高等教育出版社,1991年08月

- 30 -

发布评论

评论列表 (0)

  1. 暂无评论