一、前言
最近学习pyqt5中文教程时,最后一个例子制作了一个俄罗斯方块小游戏,由于解释的不是很清楚,所以源码有点看不懂,查找网上资料后,大概弄懂了源码的原理。
二、绘制主窗口
将主窗口居中,且设置了一个状态栏来显示三种信息:消除的行数,游戏暂停状态或者游戏结束状态。
class Tetris(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
'''initiates application UI'''
# 创建了一个Board类的实例,并设置为应用的中心组件
self.tboard = Board(self)
self.setCentralWidget(self.tboard)
# 创建一个statusbar来显示三种信息:消除的行数,游戏暂停状态或者游戏结束状态
# msg2Statusbar是一个自定义的信号,用在(和)Board类(交互),showMessage()方法是一个内建的,用来在statusbar上显示信息的方法。
self.statusbar = self.statusBar()
self.tboard.msg2Statusbar[str].connect(self.statusbar.showMessage)
self.tboard.start() # 初始化游戏
self.resize(213, 426) # 设置窗口大小
# self.setGeometry(300, 300, 500, 300)
self.center() # 窗口居中
self.setWindowTitle('Tetris') # 标题
self.show() # 展示窗口
def center(self):
'''centers the window on the screen'''
# screenGeometry()函数提供有关可用屏幕几何的信息
screen = QDesktopWidget().screenGeometry()
# 获取窗口坐标系
size = self.geometry()
# 将窗口放到中间
self.move((screen.width()-size.width())/2,
(screen.height()-size.height())/2)
其中Board类是我们后面要创建的类,主要定义了游戏的运行逻辑。
通过QDesktopWidget().screenGeometry(),获取了电脑屏幕的大小,
然后通过self.geometry()获取了主窗口的大小,将主窗口放到屏幕中央。
三、绘制俄罗斯方块的形状
以某行某列为原点,绘制俄罗斯方块的形状。
俄罗斯方块有7种基本形状,如图
每个方块形状都有四个小方块,图中的坐标显示的是小方块左上角的坐标。
定义一个Tetrominoe类,保存所有方块的形状(其实相当于后面coordsTable数组里的index)。
# Tetrominoe类保存了所有方块的形状。我们还定义了一个NoShape的空形状。
class Tetrominoe(object):
# 和Shape类里的coordsTable数组一一对应
NoShape = 0
ZShape = 1
SShape = 2
LineShape = 3
TShape = 4
SquareShape = 5
LShape = 6
MirroredLShape = 7
定义Shape类,保存类方块内部的信息。
# Shape类保存类方块内部的信息。
class Shape(object):
# coordsTable元组保存了所有的方块形状的组成。是一个构成方块的坐标模版。
coordsTable = (
((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)),
((0, 0), (1, 0), (0, 1), (1, 1)),
((-1, -1), (0, -1), (0, 0), (0, 1)),
((1, -1), (0, -1), (0, 0), (0, 1))
)
def __init__(self):
# 下面创建了一个新的空坐标数组,这个数组将用来保存方块的坐标。
self.coords = [[0,0] for i in range(4)] # 4x4的二维数组,每个元素代表方块的左上角坐标
self.pieceShape = Tetrominoe.NoShape # 方块形状,初始形状为空白
self.setShape(Tetrominoe.NoShape)
# 返回当前方块形状
def shape(self):
'''returns shape'''
return self.pieceShape
# 设置方块形状
def setShape(self, shape): # 初始shape为0
'''sets a shape'''
table = Shape.coordsTable[shape] # 从形状列表里取出其中一个方块的形状,为一个4x2的数组
for i in range(4):
for j in range(2):
self.coords[i][j] = table[i][j] # 赋给要使用的方块元素
self.pieceShape = shape # 再次获取形状(index)
# 设置一个随机的方块形状
def setRandomShape(self):
'''chooses a random shape'''
self.setShape(random.randint(1, 7))
# 小方块的x坐标,index代表第几个方块
def x(self, index):
'''returns x coordinate'''
return self.coords[index][0]
# 小方块的y坐标
def y(self, index):
'''returns y coordinate'''
return self.coords[index][1]
# 设置小方块的x坐标
def setX(self, index, x):
'''sets x coordinate'''
self.coords[index][0] = x
# 设置小方块的y坐标
def setY(self, index, y):
'''sets y coordinate'''
self.coords[index][1] = y
# 找出方块形状中位于最左边的方块的x坐标
def minX(self):
'''returns min x value'''
m = self.coords[0][0]
for i in range(4):
m = min(m, self.coords[i][0])
return m
# 找出方块形状中位于最右边的方块的x坐标
def maxX(self):
'''returns max x value'''
m = self.coords[0][0]
for i in range(4):
m = max(m, self.coords[i][0])
return m
# 找出方块形状中位于最左边的方块的y坐标
de