You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Manim中实现扇形旋转与尺寸/角度同步动画?

如何在Manim中同步执行扇形的旋转与尺寸变化动画?

嘿,我完全懂你的困扰——Transform那种先收缩再扩张的过渡确实不是想要的,咱们要的是同一个扇形一边旋转一边平滑改变大小的同步效果对吧?其实不用找太复杂的API,直接通过动画化扇形的核心属性就能实现,下面给你两种可行的方案:

方案一:用ValueTracker精准控制同步节奏

这种方法通过一个进度变量统一驱动旋转和尺寸变化,能完全自定义动画的插值逻辑,灵活性最高:

from manim import *

class Test(Scene):
    def construct(self):
        # 定义初始和目标状态的参数,以及旋转中心点
        rotate_center = SmallDot().shift(RIGHT, DOWN)
        initial_angle = 45 * DEGREES
        initial_start = 25 * DEGREES
        target_angle = 135 * DEGREES
        target_start = 185 * DEGREES
        
        # 创建初始扇形并添加到场景
        sector = Sector(
            angle=initial_angle,
            start_angle=initial_start,
            stroke_width=0,
            fill_color=RED
        ).shift(RIGHT, DOWN)
        self.add(rotate_center, sector)
        self.wait()
        
        # 用ValueTracker跟踪动画进度(0到1)
        progress = ValueTracker(0)
        
        def update_sector(mob):
            alpha = progress.get_value()
            # 线性插值计算当前的角度和起始角度
            mob.angle = interpolate(initial_angle, target_angle, alpha)
            mob.start_angle = interpolate(initial_start, target_start, alpha)
            # 计算需要旋转的总角度:目标扇形的中心角度 - 初始扇形的中心角度
            initial_center = initial_start + initial_angle / 2
            target_center = target_start + target_angle / 2
            total_rotate = target_center - initial_center
            # 应用旋转(基于当前进度)
            mob.rotate(alpha * total_rotate, about_point=rotate_center.get_center())
        
        # 绑定更新函数到扇形,播放动画
        self.play(
            progress.animate.set_value(1),
            UpdateFromFunc(sector, update_sector),
            run_time=2,
            rate_func=smooth
        )
        self.wait()

方案二:用AnimationGroup同步多个基础动画

如果不需要自定义插值逻辑,直接把旋转动画和属性修改动画放到同一个AnimationGroup里,就能实现同步效果:

from manim import *

class Test(Scene):
    def construct(self):
        rotate_center = SmallDot().shift(RIGHT, DOWN)
        sector = Sector(
            angle=45*DEGREES,
            start_angle=25*DEGREES,
            stroke_width=0,
            fill_color=RED
        ).shift(RIGHT, DOWN)
        
        self.add(rotate_center, sector)
        self.wait()
        
        # 计算总旋转角度
        initial_center = 25*DEGREES + 45*DEGREES/2
        target_center = 185*DEGREES + 135*DEGREES/2
        total_rotate = target_center - initial_center
        
        # 同步播放旋转、角度修改、起始角度修改动画
        self.play(
            Rotating(
                sector,
                axis=OUT,
                about_point=rotate_center.get_center(),
                radians=total_rotate
            ),
            ApplyMethod(sector.set_angle, 135*DEGREES),
            ApplyMethod(sector.set_start_angle, 185*DEGREES),
            run_time=2,
            rate_func=smooth
        )
        self.wait()

关键思路说明

  • 扇形的尺寸由angle(扇形角度)和start_angle(起始角度)共同决定,直接修改这两个属性就能实现尺寸变化,不需要创建新的扇形实例。
  • 旋转动画通过Rotating或者直接调用rotate()方法实现,核心是确保旋转的进度和尺寸变化的进度完全同步——两种方案都是通过统一的run_timerate_func来保证这一点的。

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

火山引擎 最新活动