You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kivy开发如何实现仅点击足球图片本身时触发移动效果

问题根源

你当前使用的collide_point是Kivy组件默认的矩形碰撞检测,会将足球图片的整个矩形边界(包括圆形周围的透明区域)都判定为有效点击区域,所以点击足球附近的透明区域也会触发事件。


解决方案1:圆形碰撞检测(推荐,适合足球这类规则圆形)

性能最优,完全适配足球的圆形形态,代码修改如下:

修改main.py中的Ball类

class Ball(Image):
    velocity = NumericProperty(0)

    def on_touch_down(self, touch):
        # 计算球的中心点坐标
        center_x = self.x + self.width / 2
        center_y = self.y + self.height / 2
        # 计算触摸点到中心点的距离平方(避免开根号提升性能)
        distance_sq = (touch.x - center_x) ** 2 + (touch.y - center_y) ** 2
        # 球的半径平方
        radius_sq = (self.width / 2) ** 2

        if distance_sq <= radius_sq:
            self.source = "icons/ball.png"
            self.velocity = 275
            # 消费当前触摸事件,阻止向下传递
            return True
        return super().on_touch_down(touch)

    def on_touch_up(self, touch):
        center_x = self.x + self.width / 2
        center_y = self.y + self.height / 2
        distance_sq = (touch.x - center_x) ** 2 + (touch.y - center_y) ** 2
        radius_sq = (self.width / 2) ** 2

        if distance_sq <= radius_sq:
            self.source = "icons/ball.png"
            return True
        return super().on_touch_up(touch)

修改KV中的Ball配置

补充图片适配参数,同时调整size到你实际需要的球的大小(当前500*500的尺寸过大,会导致碰撞范围远大于实际显示的足球):

Ball:
    source: "icons/ball.png"
    size_hint: None, None
    size: dp(80), dp(80) # 按实际需求调整尺寸
    pos_hint: {"center_x": 0.5}
    allow_stretch: True 
    keep_ratio: True # 保证球图等比例显示不变形
    id: ball

解决方案2:像素级碰撞检测(适合高精度不规则图形场景)

如果足球图片有不规则边缘或者透明区域过大,圆形检测无法满足需求,可以用像素级检测,仅点击到非透明区域才触发事件:

from kivy.graphics.texture import Texture

class Ball(Image):
    velocity = NumericProperty(0)

    def collide_pixel(self, x, y):
        # 转换为组件内部坐标
        local_x = x - self.x
        local_y = y - self.y
        tex = self.texture
        if not tex:
            return False
        # 计算图片在组件内的缩放偏移(适配keep_ratio=True的居中显示逻辑)
        tex_width, tex_height = tex.size
        widget_width, widget_height = self.size
        scale = min(widget_width / tex_width, widget_height / tex_height)
        display_width = tex_width * scale
        display_height = tex_height * scale
        offset_x = (widget_width - display_width) / 2
        offset_y = (widget_height - display_height) / 2
        # 先判断是否在图片显示区域内
        if not (offset_x <= local_x <= offset_x + display_width and offset_y <= local_y <= offset_y + display_height):
            return False
        # 转换为纹理像素坐标
        tex_x = int((local_x - offset_x) / scale)
        tex_y = int(tex_height - (local_y - offset_y) / scale)
        # 读取像素alpha值判断是否透明
        pixel = tex.get_region(tex_x, tex_y, 1, 1).pixels
        alpha = pixel[3] if len(pixel) >=4 else 255
        return alpha > 0

    def on_touch_down(self, touch):
        if self.collide_pixel(*touch.pos):
            self.source = "icons/ball.png"
            self.velocity = 275
            return True
        return super().on_touch_down(touch)
    
    # on_touch_up同理替换碰撞逻辑即可

注意事项

  • 优先使用圆形碰撞方案,性能更高,足够满足足球类圆形元素的交互需求
  • 如果球图的透明边过多,建议提前裁剪掉图片的多余透明区域,进一步提升检测精度

内容的提问来源于stack exchange,提问作者Tan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 19:54:03