参考:(https://gitbook.cn/gitchat/column/5b1a31bc862a01660e35955c/topic/5b1a86c33d723c686c3101ed)
2019-06-18
任务:绘制方块(1.定义各种方块的表示方法(类属性);2.绘制每个方块)
1.定义方块的表示方法
俄罗斯方块游戏中有七种方块,我们可以用七个大写字母表示它们:J、L、S、Z、I、T、O.
我们定义一个Piece类来表示方块,这个Piece类带有两个属性:shape表示是七种方块的哪一个方块;screen表示屏幕对象。(新建piece.py文件)
class Piece():
def __init__(self, shape, screen):
self.x = 3
self.y = 0
self.shape = shape
self.screen = screen
类名称的第一个字母最好大写,否则与文件名piece重复。知识点: Python 语言的类定义内部,赋值给属性 t 或者访问属性 t 的值,都要写作 self.t。调用方法 m,要写作 self.m。
接下来有三个问题:
1.如何记住方块的类型?
2.如何根据方块类型得出方块形状?
3.如何在游戏区域定位方块?
1.如何记住方块的类型?
我们已经创建了piece.py的文件,定义了Piece类属性,则在main.py中加入
from piece import Piece
表示引入了Piece类,并将要画方块的类型赋给piece变量:
piece = Piece('S', screen)
'S' 代表的是方块的类型;screen 是绘制方块时会用到的屏幕对象。这里'S'可以换为TLJ等其它类型。以下用'S'类型作为例子。
2.如何根据方块类型得出方块形状?
首先定义每个类型的形状矩阵,例如'S'可以这样定义:
S_SHAPE_TEMPLETE = ['.OO.',
'OO..',
'....']
大写字母O表示此处有小方块,'.'表示此处为空。
参照下图想象以下:
故定义七种方块类型的形状矩阵:
S_SHAPE_TEMPLETE = ['.OO.',
'OO..',
'....']
I_SHAPE_TEMPLETE = ['.O..',
'.O..,'
'.O..',
'.O..']
Z_SHAPE_TEMPLETE = ['OO..',
'.OO.',
'....']
T_SHAPE_TEMPLETE = ['.O..',
'OOO.',
'....']
L_SHAPE_TEMPLETE = ['.O..',
'.O..',
'.OO.',]
J_SHAPE_TEMPLETE = ['..O.',
'..O.',
'.OO.']
O_SHAPE_TEMPLETE = ['.OO',
'.OO',
'...']
定义字典PIECES: 键为表示每个形状的字母,值为上边定义的形状矩阵。
PIECES = {'S':S_SHAPE_TEMPLETE,
'I': I_SHAPE_TEMPLETE,
'Z':Z_SHAPE_TEMPLETE,
'T':T_SHAPE_TEMPLETE,
'L':L_SHAPE_TEMPLETE,
'J':J_SHAPE_TEMPLETE,
'O':O_SHAPE_TEMPLETE}
形状矩阵和字典都可以写在settings.py中,这里放的都是常量,调用时开头加一句:
from settings import *
3.如何在游戏区域定位方块?
想让'S'方块处于图中这样的位置
需让x=3,y=0。(下面解释为什么)x的范围是09,y的范围是019.这样'S'方块的定位点是第一行第四列,由于'S'的形状矩阵为:
['.OO.',
'OO..',
'....']
且'O'画 '.'不画,所以画出的'S'的四个小方块分别在一行五列、一行六列、二行四列、二行五列,如图2。
Piece类完整代码:
from settings import *
import pygame
class Piece():
def __init__(self, shape, screen):
self.x = 3
self.y = 0
self.shape = shape
self.screen = screen
def paint(self):
shape_templete = PIECES[self.shape]
for r in range(len(shape_templete)):
for c in range(len(shape_templete[0])):
if shape_templete[r][c] == 'O':
self.draw_cell(self.x+c,self.y+r)
def draw_cell(self, x, y):
cell_position = (x * CELL_WIDTH + GAME_AREA_LEFT + 1,
y * CELL_WIDTH + GAME_AREA_TOP + 1)
cell_width_height = (CELL_WIDTH - 2, CELL_WIDTH - 2)
cell_rect = pygame.Rect(cell_position, cell_width_height)
pygame.draw.rect(self.screen, CELL_COLOR, cell_rect)
paint()用作方块绘制,首先self.shape存储的是
piece = Piece('S', screen) #回看“1.如何记住方块的类型?”
中Piece类所带有的shape属性,也就是'S',故
shape_templete = PIECES[self.shape]
中 shape_templete表示的是PIECES字典中的键'S'对应的值S_SHAPE_TEMPLETE,对照形状矩阵可得:
S_SHAPE_TEMPLETE = ['.OO.',
'OO..',
'....']
是一个列表。
而这两句:
for r in range(len(shape_templete)):
for c in range(len(shape_templete[0])):
表示先按行(raw),再按列(column)依次遍历列表 S_SHAPE_TEMPLETE,遍历顺序为:0行0列、0行1列、0行2列、0行3列、1行0列、1行1列......。这样更易理解:
# 行 0 1 2
# 列 0123 0123 0123
S_SHAPE_TEMPLETE = ['.OO.', 'OO..', '. . . .']
之后进行判断,如果某行某列为'O',则这个位置要画小方块,调用draw_cell()画。
定义draw_cell():有两个属性x,y,实际上和上次绘制小方块函数差不多,都要定左上角点,定宽度高度,再画方块。
解释需让x=3,y=0:对于形状'S',paint()中遍历'O'所在行列,遍历到的第一个行列值为r=0,c=1,所以paint()中调用draw_cell(4, 0).
带入draw_cell()中,可以绘制这样一个小方块:
1.左上角坐标(4CELL_WIDTH + GAME_AREA_LEFT + 1, 0CELL_WIDTH + GAME_AREA_TOP + 1).至于每个都加1像素,可以试试去掉后什么效果。
2.该方块长宽都为CELL_WIDTH - 2.至于减2,也可以去掉试试。
绘制出这样的效果:(我把加1、减2去掉了)
对比图2看看。
最后两句显然是1.构建矩形对象2.填充矩形对象。
main()中
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
screen.fill(bg_color)
draw_game_area(screen)
# draw_cell(screen, GAME_AREA_LEFT + CELL_WIDTH * 4, GAME_AREA_TOP)
piece.paint() #加入此句绘制“piece = Piece('S', screen)”中规定的方块
pygame.display.flip()
修改为:
piece = Piece('T', screen)
则有
明天继续!