本文教你使用 Kivy 的 PushMatrix/PopMatrix 与 Rotate 指令,结合鼠标坐标实时计算角度,让矩形(如炮塔)始终以其短边垂直指向鼠标位置,实现精准的动态旋转交互。
本文教你使用 kivy 的 `pushmatrix`/`popmatrix` 与 `rotate` 指令,结合鼠标坐标实时计算角度,让矩形(如炮塔)始终以其短边垂直指向鼠标位置,实现精准的动态旋转交互。
在 Kivy 中实现“鼠标跟随旋转”效果(例如炮塔自动瞄准),关键在于动态计算鼠标相对于目标锚点的角度,并在每次鼠标移动时重绘旋转后的图形。Kivy 的图形指令不支持直接修改已有 Rectangle 的旋转属性,因此需采用「清空画布 → 应用变换 → 绘制新图形」的模式。
核心原理:坐标系变换 + 角度计算
我们以矩形的中心线(或某固定参考点,如本例中的 fixed_point)为旋转原点,利用 math.atan2(dy, dx) 计算从该点指向鼠标的向量夹角(单位:弧度),再转为度数供 Rotate 使用。注意:Kivy 的 Rotate 默认绕 (0, 0) 旋转,必须显式指定 origin= 参数将其锚定到目标位置。
完整实现步骤
- 定义旋转锚点:本例将 fixed_point 设为矩形左侧中点(即 (x, y + height/2)),使旋转后“短边”自然朝向鼠标;
- 绑定鼠标事件:使用 Window.bind(mouse_pos=...) 监听全局鼠标坐标变化;
- 实时更新画布:在回调函数中调用 self.canvas.clear(),避免图形残留;再通过 PushMatrix → Rotate → Rectangle → PopMatrix 构建变换上下文。
以下是精简优化后的核心代码(已修复原示例中的类名冲突与初始化问题):
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 = (100, 100) # 初始位置
# 以矩形左侧中点为旋转中心(实现"短边垂直指向鼠标")
self.fixed_point = (self.cannon_pos[0], self.cannon_pos[1] + self.cannon_size[1] / 2)
Window.bind(mouse_pos=self.update_cannon_rotation)
def update_cannon_rotation(self, *args):
mouse_x, mouse_y = Window.mouse_pos
# 计算相对向量
delta_x = mouse_x - self.fixed_point[0]
delta_y = mouse_y - self.fixed_point[1]
# atan2 返回 [-π, π],转为 [0, 360) 度(Kivy Rotate 顺时针为正)
self.cannon_angle = math.degrees(math.atan2(delta_y, delta_x))
# 清空并重绘
self.canvas.clear()
with self.canvas:
PushMatrix()
# 关键:指定 origin 实现绕指定点旋转
Rotate(angle=self.cannon_angle, origin=self.fixed_point)
Color(0.2, 0.6, 0.8, 1) # 蓝色矩形
Rectangle(pos=self.cannon_pos, size=self.cannon_size)
PopMatrix()
class Myapp(ScreenManager):
pass
class MyApp(App):
def build(self):
return Myapp()
注意事项与最佳实践
- ✅ canvas.clear() 不可省略:否则每次绘制会叠加旧图形,造成严重性能下降与视觉混乱;
- ⚠️ mouse_pos 坐标系是窗口绝对坐标,若需适配缩放或多屏,请结合 Window.size 归一化处理;
- ? 若需更高性能(如高频更新),可改用 InstructionGroup 缓存非变换指令,仅更新 Rotate 参数;
- ? “短边垂直指向鼠标”的几何本质是:让矩形的局部 Y 轴(默认向上)对齐鼠标方向向量——这正是 atan2(dy, dx) 所求的方位角。
通过此方法,你不仅能实现炮塔瞄准,还可拓展至雷达扫描、指针导向、动态 UI 反馈等场景。记住:Kivy 图形系统是声明式的,状态驱动而非属性绑定,主动管理画布生命周期是流畅交互的关键。










