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

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

之前做过python tkinter实现俄罗斯方块的教程:
https://www.bilibili.com/video/BV1eJ411h7ZV
对应博客:https://blog.csdn.net/python1639er/article/details/104069590

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

由于我自己玩的时候感觉不卡(三五分钟都没啥卡顿感觉)
所以当时没有细想,以为是他们电脑配置或者改了代码的原因。

直到前不久,我直播写代码的时候,有个老哥又提到了这个卡顿的问题。
当时刚好有空,仔细看了下代码,发现确实有问题会导致卡顿。

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

是清理方块的方式有问题

游戏里面清理方块的方式:
是通过绘制一个新的背景色的方格覆盖来实现的。

具体的来讲

  • 当俄罗斯方块下落(左右移动同理)时
    其过程如示意图

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

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

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

每一次清理都会新增R*C个方块进行绘制
代码里面行数R为12,列数C为20
所以总数为240。
即每一次清理都会新增240个。

问题来了,所有这些新增的方块从未被清理过。
那么我们不难发现,随着时间的推移,方块越来越多,游戏因此越来越卡顿。

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

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

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

补充说明:
用背景色覆盖来进行清理的方法,在pygame里面经常会用到。
其在pygame里面应该是不会卡顿的,因为pygame的具体机制有些不同。

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

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

这里我们用该方法通过tag去删除已绘制的对象
代码示例如下

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

代码思路

既然要通过tag来删除绘制对象,那么我们就需要思考应该有几种tag。
或者说,有几种要清理的场景

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

  1. 正在下落的俄罗斯方块,移动时要清理移动之前的俄罗斯方块。
    那么对正在下落的俄罗斯方块,不妨记其tag为"falling"
    移动正在下落的俄罗斯方块后,先清理掉tag为"falling"的,再绘制一遍俄罗斯方块。
  2. 已经落地的俄罗斯方块,凑齐一行后需要按行来清除。
    那么对于这些方块,记其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(雾

python tkinter实现俄罗斯方块基础版 —— 五、后续优化相关推荐

  1. python tkinter实现俄罗斯方块基础版——四、消除与得分

    总目录 一.基础界面 二.界面动起来 三.生成.移动.固定.消除 四.消除与得分 ======================= 大爽歌作,made by big shuang =========== ...

  2. python俄罗斯方块教程_python tkinter实现俄罗斯方块 基础版

    本项目最终效果见本人b站投稿av81480858 简介部分 本项目最终代码已上传github: https://github.com/BigShuang/Tetris 的1_BASIC文件夹 .其中1 ...

  3. python俄罗斯方块的消除算法_1.1.3python tkinter实现俄罗斯方块基础版-生成、移动、固定、消除...

    1.随机生成俄罗斯方块 这里需要导入python自带的随机库random 使用其中的choice方法,从俄罗斯方块形状列表中随机选出一个. 该方法源码说明如图 首先我们需要删除原来的位于game_lo ...

  4. python俄罗斯方块代码34行_python turtle实现俄罗斯方块 基础版

    本项目通过python自带库tkinter实现,无需安装第三方库 本项目基于python3版本开发(如果你的是python2.x,运行可能会有问题) 一.基础界面 1 搭建基础窗体 使用tkinter ...

  5. 用python语言实现反恐精英基础版-案例

    """ 写了大概有1个多小时吧,中途多多少少都出现了一些bug,最终还是码出来,Talk is cheap, show me code!(屁话少说,放码过来) PS:Ma ...

  6. 反恐精英ol永恒python武器强化_用python语言实现反恐精英基础版-案例

    """ 写了大概有1个多小时吧,中途多多少少都出现了一些bug,最终还是码出来,Talk is cheap, show me code!(屁话少说,放码过来) PS:Ma ...

  7. Python数据结构与算法基础|第五期:代码实现——循环队列的链式存储结构

    在上一次,我们通过取余等数学方法实现了顺序存储的循环队列.由于我们使用的是Python内置的列表类型作为底层,实际上我们的存储空间并不是首尾相连的.下面,我们使用链式存储结构来实现一个真正首尾相连的循 ...

  8. python实现实例_用python语言实现斗地主基础版-案例

    Talk is cheap, show me code!(屁话少说,放码过来) """ 案例斗地主分析: 1.扑克牌作为对象呈现 2.创建未发牌的牌堆的列表 3.创建三个 ...

  9. 小白都看得懂的使用Python生成随机验证码图片,以及后续优化方案

    环境:Anaconda3-2020.02 首先我们分解一下需要做什么: 生成随机的字母字符串 生成生成随机的背景色 生成随机的字体颜色 把随机的字符串用随机的颜色渲染,然后放到一块随机的背景色上面,基 ...

最新文章

  1. mac 思科 链路聚合_EtherChannel Cisco 端口聚合详解
  2. kafka发送及消费消息示例
  3. SPOJ1812 LCS2
  4. HttpModules 管道过滤 自定义页面
  5. 关于sqoop增量导入oracle的数据到HDFS的出现的错误总结
  6. java future模式 所线程实现异步调用
  7. [渝粤教育] 江西财经大学 实用英语演讲 参考 资料
  8. 【软件开发规范五】《用户需求及规格说明书》
  9. Power BI 数据分析可视化软件入门教程
  10. VMP.Net 3.5 脱壳
  11. 其他干货——文章投稿之图片格式-位图vs.矢量图
  12. Unity 使用Excel 读取文件 所碰到的坑 使用Excel.dll读取
  13. java treemap 排序原理_Java TreeMap排序算法实例
  14. 国内那些靠谱些的招聘网站
  15. 戴尔微型计算机怎么换硬盘,教你如何给DELL台式电脑换硬盘
  16. 网友发帖问阿里P7和协和主治医师谁更成功,BAT员工纷纷嘲笑.
  17. 【Matlab生物电信号】生物电信号仿真【含GUI源码 684期】
  18. siri语音功能测试点
  19. 什么是linux网络驱动程序,什么是Linux网卡驱动程序?
  20. 计算机828专业课包括哪些,上海海事大学计算机软工专业课828数据结构及程序设计复习指导...

热门文章

  1. Trojan-Spy.Win32.Pophot.afw 木马类
  2. 计算机应用基础考试高起专,计算机应用基础试题(高起专)
  3. 班级成绩的输入和输出
  4. ddr2服务器性能强吗,华硕服务器及服务器主板搭载DDR2技术 ,实现性能的全新突破...
  5. 第四章 自适应滤波 笔记
  6. 新工科背景下计算机类专业英语教学,外国语学院教师参加“新工科背景下高校外语教学改革与专业建设高端论坛”...
  7. ipad 键盘 滚动屏幕_为什么iPad上没有显示屏幕键盘?
  8. 人工智能之父,关于两个“爸爸”的事情,你不想了解一下吗?(楚才国科)
  9. 第八周周一物联网通信
  10. 猎豹2018秋招编程题2