Kivy开发:如何实现鼠标周围指定半径内可见、其余区域遮挡的效果?
实现思路
- 核心用Kivy内置的**模板缓冲区(Stencil Buffer)**实现区域裁剪,这是实现指定区域可见效果的最优方案,不需要手动处理像素级渲染,性能也足够。
- 层级绘制逻辑按以下顺序处理:
- 底层绘制迷宫原图,这部分和你现有代码保持一致
- 在顶层绘制全黑遮罩时,通过模板裁剪将鼠标位置对应半径的圆形区域挖空,仅该挖空区域可以看到下方的迷宫,其余区域被黑色遮罩覆盖
- 不需要保留探索记录,所以每次鼠标移动时仅更新裁剪圆形的位置,全量重绘遮罩即可,不需要存储历史坐标
- 监听鼠标移动事件更新圆形位置,Kivy中可以通过
on_touch_move方法捕获鼠标移动的坐标,注意做坐标转换避免错位
具体实现修改
Python代码修改
from kivy.app import App from kivy.uix.gridlayout import GridLayout from kivy.config import Config Config.set('graphics', 'width', '806') Config.set('graphics', 'height', '706') class MyGrid(GridLayout): # 可见区域半径,可自行调整数值 visibility_radius = 70 def __init__(self, **kwargs): super().__init__(**kwargs) # 初始化鼠标位置,可自行调整初始值 self.mouse_pos = (0, 0) def on_touch_move(self, touch): # 转换坐标为当前组件的相对坐标,避免嵌套布局导致错位 self.mouse_pos = self.to_widget(*touch.pos) # 触发画布重绘 self.canvas.ask_update() class DrawingWindow(App): def build(self): return MyGrid() if __name__ == "__main__": DrawingWindow().run()
kv代码修改
<MyGrid>: cols:1 size: 806,706 canvas: # 底层绘制迷宫原图 Rectangle: size: self.size source: 'Puzzle.png' canvas.after: # 模板压栈,开始裁剪逻辑 StencilPush # 绘制裁剪用的圆形,位置跟随鼠标 Ellipse: pos: (self.mouse_pos[0] - self.visibility_radius, self.mouse_pos[1] - self.visibility_radius) size: (self.visibility_radius*2, self.visibility_radius*2) # 反转模板,使裁剪区域变为圆形以外的部分 StencilUse StencilInvert # 绘制全黑遮罩,仅模板允许的区域(圆形以外)会被渲染 Color: rgba: 0,0,0,1 Rectangle: size: self.size # 模板出栈,避免影响其他组件绘制 StencilPop
补充说明
- 如果需要调整可见范围,直接修改
visibility_radius的数值即可 - 如果出现圆形位置和鼠标指针错位,检查是否有嵌套布局的坐标偏移,用
to_widget方法处理即可 - 不需要额外的逻辑处理已探索区域,因为每次重绘都会刷新遮罩,不会保留之前的可见区域记录
内容的提问来源于stack exchange,提问作者Igor Markovic
相关产品推荐
相关产品推荐

