如何在 Kivy 中实现鼠标驱动的部件旋转(以炮台式矩形为例)

落晨小哥_5941

落晨小哥_5941

2026-04-15

233人浏览

原创

本文详解如何使用 Kivy 的 PushMatrix/PopMatrix 与 Rotate 指令,结合鼠标位置实时计算角度,使矩形(如炮台)始终朝向鼠标,实现动态旋转交互。

本文详解如何使用 kivy 的 `pushmatrix`/`popmatrix` 与 `rotate` 指令,结合鼠标位置实时计算角度,使矩形(如炮台)始终朝向鼠标,实现动态旋转交互。

在 Kivy 中,直接修改 Widget 的 rotation 属性无法精准控制旋转中心或实现“指向鼠标”的语义(因其默认绕自身中心旋转)。正确做法是:在画布(canvas)中动态重绘,并利用 OpenGL 变换指令实现以指定锚点为中心的实时旋转变换。

核心思路如下:

  • 定义一个固定旋转原点(例如矩形的中心线顶端,模拟炮管枢轴点);
  • 在每次鼠标移动时,计算从该原点指向鼠标的向量夹角;
  • 使用 PushMatrix + Rotate(angle=..., origin=...) 包裹图形绘制指令,确保旋转围绕指定点发生;
  • 调用 self.canvas.clear() 避免旧图形残留(注意:此方式适用于简单动态对象;复杂场景建议使用 InstructionGroup 或自定义 Canvas 管理)。

以下是关键代码实现(已优化结构与健壮性):

from kivy.core.window import Window
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.app import App
from kivy.uix.widget import Widget
import math
from kivy.graphics import Color, Rectangle, PushMatrix, PopMatrix, Rotate
from kivy.config import Config

Config.set('graphics', 'resizable', True)


class MenuScreen(Screen):
    pass


class Game(Screen):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.cannon_size = (150, 50)
        self.cannon_pos = (300, 200)  # 初始位置(可居中:Window.width//2 - 75, Window.height//2 - 25)
        # 旋转中心设为矩形顶部中点(即“炮管转轴”)
        self.pivot = (self.cannon_pos[0] + self.cannon_size[0] / 2,
                      self.cannon_pos[1] + self.cannon_size[1])
        self.cannon_angle = 0

        # 绑定鼠标移动事件(注意:mouse_pos 是窗口坐标,需确保窗口已初始化)
        Window.bind(mouse_pos=self.update_cannon_rotation)

    def update_cannon_rotation(self, *args):
        mouse_x, mouse_y = Window.mouse_pos
        # 计算相对于 pivot 的向量
        dx = mouse_x - self.pivot[0]
        dy = mouse_y - self.pivot[1]
        # atan2 返回 [-π, π],转为 [0, 360) 度,且适配 Kivy Y 轴向下惯例
        # 注意:Kivy 的 Rotate 正方向为逆时针,而视觉上“指向鼠标”需补偿 90°(因矩形默认水平放置,长边在X轴)
        self.cannon_angle = math.degrees(math.atan2(dy, dx)) - 90

        # 清空画布并重绘
        self.canvas.clear()
        with self.canvas:
            PushMatrix()
            # 关键:以 pivot 为原点旋转
            Rotate(angle=self.cannon_angle, origin=self.pivot)
            Color(0.2, 0.6, 1, 1)  # 蓝色炮管
            Rectangle(pos=self.cannon_pos, size=self.cannon_size)
            PopMatrix()

    def on_enter(self):
        # 进入游戏屏时确保初始绘制
        self.update_cannon_rotation()


class Myapp(ScreenManager):
    pass


class MyApp(App):
    def build(self):
        return Myapp()


if __name__ == '__main__':
    MyApp().run()

? 注意事项与最佳实践:

  • ✅ Window.mouse_pos 返回的是窗口绝对坐标,不受 widget 坐标系影响,适合全局定位;
  • ⚠️ canvas.clear() 会清除整个 widget 的 canvas,若界面含其他静态元素(如背景),应将其绘制在 canvas.before 或独立 widget 中;
  • ? 若需更高性能(如高频更新),避免每帧 clear() + 全量重绘,改用 InstructionGroup 缓存非动态部分,仅更新 Rotate 指令参数;
  • ? 角度计算中 -90 补偿源于 Kivy 默认矩形沿 X 轴正向延伸(→),而“炮管朝向鼠标”要求其“前端”(即矩形右侧中点)对准鼠标——故需将初始朝向由 0°(东)校正为 -90°(北),再叠加动态偏移;
  • ? 实际项目中,建议将旋转逻辑封装为可复用的 RotatableSprite 类,并支持缩放、锚点配置等扩展能力。

通过本方案,你不仅能实现鼠标跟随旋转,更掌握了 Kivy 底层画布变换的核心范式:状态隔离(PushMatrix/PopMatrix)、原点控制(origin)、以及向量几何驱动的交互逻辑——这是构建游戏、可视化工具或高级 UI 的关键基础。

驱动精灵
驱动精灵

驱动精灵基于驱动之家十余年的专业数据积累,驱动支持度高,已经为数亿用户解决了各种电脑驱动问题、系统故障,是目前有效的驱动软件,有需要的小伙伴快来保存下载体验吧!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

2023.07.20

1711

4

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

2023.07.25

4364

7

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.31

1689

3

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

2023.08.03

25497

23

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

3107

5

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

3127

5

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

1163

5

python合并两个列表
python合并两个列表

Python是一种强大的编程语言,具有许多方便的功能和工具。在Python中,有多种方法可以合并两个列表。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.10

596

4

python是前端还是后端
python是前端还是后端

Python属于前端也属于后端,其灵活性和丰富的生态系统使得开发人员能够在不同的领域中灵活运用。本专题为大家提供python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

2423

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.6万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.4万人学习