1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > python tkinter实现俄罗斯方块基础版 —— 五 后续优化

python tkinter实现俄罗斯方块基础版 —— 五 后续优化

时间:2020-11-29 10:10:30

相关推荐

python tkinter实现俄罗斯方块基础版 —— 五 后续优化

作者自我介绍:大爽歌, b站小UP主 ,直播编程+红警三 ,python1对1辅导老师 。

1 - 答评论问——卡顿优化

之前做过python tkinter实现俄罗斯方块的教程:

/video/BV1eJ411h7ZV

对应博客:/python1639er/article/details/104069590

后来有一些观众朋友反馈:玩到后面特别的卡顿。

由于我自己玩的时候感觉不卡(三五分钟都没啥卡顿感觉)

所以当时没有细想,以为是他们电脑配置或者改了代码的原因。

直到前不久,我直播写代码的时候,有个老哥又提到了这个卡顿的问题。

当时刚好有空,仔细看了下代码,发现确实有问题会导致卡顿。

那是什么问题导致了卡顿呢

是清理方块的方式有问题

游戏里面清理方块的方式:

是通过绘制一个新的背景色的方格覆盖来实现的。

具体的来讲

当俄罗斯方块下落(左右移动同理)时

其过程如示意图

每一次移动都会新增四个方块进行绘制。

当下落的俄罗斯方块填满一行,要清除的时候

代码里面是重新绘制整个面板所有方块。

每一次清理都会新增R*C个方块进行绘制

代码里面行数R为12,列数C为20

所以总数为240。

即每一次清理都会新增240个。

问题来了,所有这些新增的方块从未被清理过。

那么我们不难发现,随着时间的推移,方块越来越多,游戏因此越来越卡顿。

那么这个问题怎么解决呢?

修改清理方式,之前是通过用背景色覆盖来假清理。

下来我们需要想办法,对要去除的方块,实现真正的清理。

补充说明:

用背景色覆盖来进行清理的方法,在pygame里面经常会用到。

其在pygame里面应该是不会卡顿的,因为pygame的具体机制有些不同。

tkinterCanvas类 提供了类方法delete来实现这样的清理。

该方法的详细解释可以看我最近的博客文章:

tkinter Canvas delete 方法详解

这里我们用该方法通过tag去删除已绘制的对象

代码示例如下

canvas.create_rectangle(50, 50, 100, 150, fill="red", tag="one") # 绘制canvas.delete("one") # 清除tag为"one"的绘制对象,即上面的绘制

代码思路

既然要通过tag来删除绘制对象,那么我们就需要思考应该有几种tag。

或者说,有几种要清理的场景

通过上文的分析,不难想到有两种。

正在下落的俄罗斯方块,移动时要清理移动之前的俄罗斯方块。

那么对正在下落的俄罗斯方块,不妨记其tag为"falling"

移动正在下落的俄罗斯方块后,先清理掉tag为"falling"的,再绘制一遍俄罗斯方块。已经落地的俄罗斯方块,凑齐一行后需要按行来清除。

那么对于这些方块,记其tag为"row-%s" % r

所以tag有两类

"falling""row-%s" % r,记其 tag_kind 为"row"

而背景色方块只需要游戏开始时绘制一遍,后面不用再绘制,所以不需要清理,不设置tag。

修改draw_cell_by_cr

原来的draw_cell_by_cr

def draw_cell_by_cr(canvas, c, r, color="#CCCCCC"):x0 = c * cell_sizey0 = r * cell_sizex1 = c * cell_size + cell_sizey1 = r * cell_size + cell_sizecanvas.create_rectangle(x0, y0, x1, y1,fill=color, outline="white", width=2)

修改后为

def draw_cell_by_cr(canvas, c, r, color="#CCCCCC", tag_kind=""):x0 = c * cell_sizey0 = r * cell_sizex1 = c * cell_size + cell_sizey1 = r * cell_size + cell_sizeif tag_kind == "falling":canvas.create_rectangle(x0, y0, x1, y1, fill=color,outline="white", width=2, tag=tag_kind)elif tag_kind == "row":canvas.create_rectangle(x0, y0, x1, y1, fill=color, outline="white", width=2, tag="row-%s" % r)else:canvas.create_rectangle(x0, y0, x1, y1, fill=color, outline="white", width=2)

修改对draw_cell_by_cr的调用

draw_board

原来为

def draw_board(canvas, block_list):for ri in range(R):for ci in range(C):cell_type = block_list[ri][ci]if cell_type:draw_cell_by_cr(canvas, ci, ri, SHAPESCOLOR[cell_type])else:draw_cell_by_cr(canvas, ci, ri)

修改后为

# 绘制面板, 只有在第一次绘制时才绘制背景色方块def draw_board(canvas, block_list, isFirst=False):# 删掉原来所有的行for ri in range(R):canvas.delete("row-%s" % ri)for ri in range(R):for ci in range(C):cell_type = block_list[ri][ci]if cell_type:draw_cell_by_cr(canvas, ci, ri, SHAPESCOLOR[cell_type], tag_kind="row")elif isFirst:draw_cell_by_cr(canvas, ci, ri)

同时修改原来,初始调用draw_board的代码(大概在91行左右的地方)

修改原来的draw_board(canvas, block_list)

draw_board(canvas, block_list, True)

draw_cells

原来为

def draw_cells(canvas, c, r, cell_list, color="#CCCCCC"):for cell in cell_list:cell_c, cell_r = cellci = cell_c + cri = cell_r + r# 判断该位置方格在画板内部(画板外部的方格不再绘制)if 0 <= c < C and 0 <= r < R:draw_cell_by_cr(canvas, ci, ri, color)

修改后为

def draw_cells(canvas, c, r, cell_list, color="#CCCCCC"):for cell in cell_list:cell_c, cell_r = cellci = cell_c + cri = cell_r + r# 判断该位置方格在画板内部(画板外部的方格不再绘制)if 0 <= c < C and 0 <= r < R:draw_cell_by_cr(canvas, ci, ri, color, tag_kind="falling")

draw_block_move

原来为

def draw_block_move(canvas, block, direction=[0, 0]):shape_type = block['kind']c, r = block['cr']cell_list = block['cell_list']# 移动前,先清除原有位置绘制的俄罗斯方块,也就是用背景色绘制原有的俄罗斯方块draw_cells(canvas, c, r, cell_list)dc, dr = directionnew_c, new_r = c+dc, r+drblock['cr'] = [new_c, new_r]# 在新位置绘制新的俄罗斯方块就好draw_cells(canvas, new_c, new_r, cell_list, SHAPESCOLOR[shape_type])

修改后为

def draw_block_move(canvas, block, direction=[0, 0]):shape_type = block['kind']c, r = block['cr']cell_list = block['cell_list']# 移动前,清除原有位置绘制的俄罗斯方块canvas.delete("falling")dc, dr = directionnew_c, new_r = c+dc, r+drblock['cr'] = [new_c, new_r]# 在新位置绘制新的俄罗斯方块就好draw_cells(canvas, new_c, new_r, cell_list, SHAPESCOLOR[shape_type])

save_block_to_list

原来为

def save_block_to_list(block):shape_type = block['kind']cc, cr = block['cr']cell_list = block['cell_list']for cell in cell_list:cell_c, cell_r = cellc = cell_c + ccr = cell_r + cr# block_list 在对应位置记下其类型draw_cellsblock_list[r][c] = shape_type

修改后为

def save_block_to_list(block):# 清除原有的打上了 falling 标签的方块canvas.delete("falling")shape_type = block['kind']cc, cr = block['cr']cell_list = block['cell_list']for cell in cell_list:cell_c, cell_r = cellc = cell_c + ccr = cell_r + cr# block_list 在对应位置记下其类型block_list[r][c] = shape_typedraw_cell_by_cr(canvas, c, r, SHAPESCOLOR[shape_type], tag_kind="row")

到这里,就改好了。

此时运行软件,应该就没有越玩越卡顿的问题了。

如果还卡,那可能又有其他bug(雾

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。