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

ReplacementTransform动画为何表现不一致?

ReplacementTransform连续使用出现残留的原因与解决方法

我参考Manim社区版官方文档修改了示例代码,添加更多数字后运行出现异常:

class ReplacementTransformOrTransform(Scene):
    def construct(self):
        # set up the numbers
        r_transform = VGroup(*[Integer(i) for i in range(1, 5)])
        text_1 = Text("ReplacementTransform", color=RED)
        r_transform.add(text_1)

        transform = VGroup(*[Integer(i) for i in range(5, 9)])
        text_2 = Text("Transform", color=BLUE)
        transform.add(text_2)

        ints = VGroup(r_transform, transform)
        texts = VGroup(text_1, text_2).scale(0.75)
        r_transform.arrange(direction=UP, buff=1)
        transform.arrange(direction=UP, buff=1)

        ints.arrange(buff=2)
        self.add(ints, texts)

        # The mobs replace each other and none are left behind
        self.play(ReplacementTransform(r_transform[0], r_transform[1]))
        self.play(ReplacementTransform(r_transform[1], r_transform[2]))
        self.play(ReplacementTransform(r_transform[2], r_transform[3]))

        # The mobs linger after the Transform()
        self.play(Transform(transform[0], transform[1]))
        self.play(Transform(transform[1], transform[2]))
        self.play(Transform(transform[2], transform[3]))
        self.wait()

运行后现象:

  • 数字1转换为2,无残留;
  • 数字2转换为3,无残留;
  • 数字3转换为4时,却留下了另一个3(表现与普通Transform一致)。

环境:Python 3.13.1 + Manim社区版0.19.0(均为最新版本)


原因分析

问题出在VGroup的索引会随ReplacementTransform操作动态改变:

  1. 初始r_transform的元素顺序是[1,2,3,4,text1](索引0到4);
  2. 第一次执行ReplacementTransform(r_transform[0], r_transform[1])后,源对象1会被从r_transform中移除,此时r_transform变为[2,3,4,text1](索引0到3);
  3. 第二次执行ReplacementTransform(r_transform[1], r_transform[2])时,你以为操作的是2→3,但实际r_transform[1]已经变成了原来的3,r_transform[2]是原来的4,这一步实际是把3替换成4,操作后r_transform变为[2,4,text1](索引0到2);
  4. 第三次执行ReplacementTransform(r_transform[2], r_transform[3])时,r_transform[3]根本不存在(此时r_transform只有3个元素),Manim的 fallback 逻辑导致这次操作没有正确执行ReplacementTransform的移除行为,反而留下了残留。

简言之:依赖VGroup的索引获取操作对象,但每次ReplacementTransform都会删除源对象、改变VGroup结构,导致后续索引指向的不是你预期的数字。


解决方法

提前将需要操作的每个数字保存为独立变量,避免依赖动态变化的VGroup索引:

修改后的代码:

class ReplacementTransformOrTransform(Scene):
    def construct(self):
        # 提前保存每个数字为独立变量
        num1 = Integer(1)
        num2 = Integer(2)
        num3 = Integer(3)
        num4 = Integer(4)
        r_transform = VGroup(num1, num2, num3, num4)
        text_1 = Text("ReplacementTransform", color=RED)
        r_transform.add(text_1)

        num5 = Integer(5)
        num6 = Integer(6)
        num7 = Integer(7)
        num8 = Integer(8)
        transform = VGroup(num5, num6, num7, num8)
        text_2 = Text("Transform", color=BLUE)
        transform.add(text_2)

        ints = VGroup(r_transform, transform)
        texts = VGroup(text_1, text_2).scale(0.75)
        r_transform.arrange(direction=UP, buff=1)
        transform.arrange(direction=UP, buff=1)

        ints.arrange(buff=2)
        self.add(ints, texts)

        # 使用独立变量执行替换,索引不会混乱
        self.play(ReplacementTransform(num1, num2))
        self.play(ReplacementTransform(num2, num3))
        self.play(ReplacementTransform(num3, num4))

        # Transform部分同理可优化,保持原有逻辑也能运行
        self.play(Transform(transform[0], transform[1]))
        self.play(Transform(transform[1], transform[2]))
        self.play(Transform(transform[2], transform[3]))
        self.wait()

这样每次ReplacementTransform操作的都是你明确指定的数字,不会因为VGroup结构变化导致索引错位,就能实现连续替换且无残留的效果。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 21:19:54