跳转至

动画

影片代码
import manimgx as m


class AnimationsHero(m.Scene):
    def construct(self) -> None:
        square = m.Square(color=m.BLUE, fill_opacity=0.5)
        circle = m.Circle(color=m.PINK, fill_opacity=0.5)
        self.play(m.Create(square))
        self.play(square.animate.shift(2 * m.LEFT).rotate(m.PI / 4))
        self.play(m.Transform(square, circle))
        self.play(m.Indicate(square))
        self.play(square.animate.set_color(m.YELLOW).shift(2 * m.RIGHT))
        self.wait()

动画随时间改变 mobject。play 播放它:场景的时间在动画的 run_time 内运行(默认 1 秒,除非你指定其他值),每一帧显示该时刻的变化。其 rate_func 为其把握节奏:先慢、后快、再慢,除非你指定其他值。

方法所做的任何变化都可以动画化:在方法前加上 .animate, 即 self.play(square.animate.shift(m.RIGHT))。下面的动画实现方法无法做到的变化: 绘制一个图形、书写一段文本、将一个 mobject 变为另一个、闪烁某个点。多个动画可以在 一次 play 中同时播放,也可以在一个组中依次播放。

  • 为变化添加动画


    .animate:任意方法调用,动画化。移动到目标,或回到已保存的状态。

  • 速率函数


    动画如何把握节奏:平滑地、匀速地、带弹跳或带摆动。

  • 出现与消失


    绘制、书写、淡入和生长 mobject,并将它们再次移出。

  • 变换


    将一个 mobject 变为另一个,匹配两个公式的各部分,交换位置。

  • 移动与变形


    绕某点旋转、沿路径移动,或让每个点经过某个函数。

  • 强调


    吸引视线:指示、圈住、闪烁、摆动。

  • 同时与依次


    同时播放动画、依次播放,或每个在前一个之后稍后播放。

动画

每个动画都接受动画关键字:运行多久、如何把握节奏,以及其各部分如何依次开始。

AnimationOptions

每个动画按关键字接收的选项。

每个动画类为它们设置自己的默认值:例如 Create 将 mobject 的各部分一个接一个地绘制(lag_ratio=1)。

run_time

动画播放时长,以秒为单位(默认 1)。

lag_ratio

mobject 各部分如何交错:每个部分在其前一个部分开始后,经过其运行时长的该分数比例后开始 (默认 0:全部同时;1:一个接一个)。

rate_func

动画进度如何随时间运行:一个从 [0, 1] 到 [0, 1] 的函数 (默认为 smooth;参见 rate functions)。

reverse_rate_function

是否反向运行动画(默认 False)。

name

动画的名称。

remover

动画结束时 mobject 是否离开场景 (默认 False)。

suspend_mobject_updating

动画期间 mobject 的更新器是否在其下运行(默认 True):它们 持续作用于 mobject,每一帧显示动画应用于其结果。 若为 False,则它们作用于被动画的 mobject 本身。

introducer

动画开始时 mobject 是否加入场景(默认 False); 否则若场景缺少它,play 在其开始时将其带入。

use_override

若某 mobject 的类用另一个动画代替此动画播放,是否如此执行 (默认 True)。

run_time

动画播放时长,以秒为单位(默认 1)。

rate_func

动画进度如何随时间运行:一个从 [0, 1] 到 [0, 1] 的函数 (默认为 smooth;参见 rate functions)。

lag_ratio

mobject 各部分如何交错:每个部分在其前一个部分开始后,经过其运行时长的该分数比例后开始 (默认 0:全部同时;1:一个接一个)。

reverse_rate_function

是否反向运行动画(默认 False)。

remover

动画结束时 mobject 是否离开场景 (默认 False)。

introducer

动画开始时 mobject 是否加入场景(默认 False); 否则若场景缺少它,play 在其开始时将其带入。

suspend_mobject_updating

动画期间 mobject 的更新器是否在其下运行(默认 True):它们 持续作用于 mobject,每一帧显示动画应用于其结果。 若为 False,则它们作用于被动画的 mobject 本身。

use_override

若某 mobject 的类用另一个动画代替此动画播放,是否如此执行 (默认 True)。

name

动画的名称。

Animation

代码
import manimgx as m


class DropIn(m.Animation):
    def interpolate_submobject(
        self, submobject: m.Mobject, start: m.Mobject, alpha: float
    ) -> None:
        submobject.points = start.points
        submobject.shift((1 - alpha) * 2 * m.UP).set_opacity(alpha)


class AnimationExample(m.Scene):
    def construct(self) -> None:
        word = m.Text("manimgx", font_size=144)
        self.play(DropIn(word, lag_ratio=0.3, run_time=2))

mobject 在一段场景时间内的变化。

动画播放 run_time 秒的场景时间。其进度 alpha 从开始时的 0 到结束时的 1,由其速率函数缓急(默认为 smooth:慢、快、慢)。其 mobject 的各部分(其家族中 有点的成员)可以交错:通过 lag_ratio,每个部分在其前一个部分开始后, 经过其运行时长的该分数比例后开始,因此 0 使它们全部同时移动, 1 使它们一个接一个。

Scene.play 播放它。带入其 mobject 的动画在开始时将其 加入场景,而取出其 mobject 的动画在结束时将其移除。mobject 自身的更新器在播放 期间持续运行:每一帧显示动画应用于更新器当时所得到的 mobject,当动画 结束时,mobject 即为其最后一帧所示的状态。

要制作自己的动画,请从它派生一个类,并重写 interpolate_mobject:它在速率函数 缓急之前,将整个 mobject 设置为动画的进度(从 0 到 1),因此需自行应用 self.rate_func(alpha)。各选项是同名的属性 (self.rate_func、self.lag_ratio、…)。Animation 本身 不改变任何内容:它将其 mobject 在场景中保持其运行时长。

m.Animation(mobject, **options)
mobject

要动画的 mobject;None 表示无,如 Wait 所具有的。

run_time

动画播放时长,以秒为单位(默认 1)。

lag_ratio

mobject 各部分如何交错:每个部分在其前一个部分开始后,经过其运行时长的该分数比例后开始 (默认 0:全部同时;1:一个接一个)。

rate_func

动画进度如何随时间运行:一个从 [0, 1] 到 [0, 1] 的函数 (默认为 smooth;参见 rate functions)。

reverse_rate_function

是否反向运行动画(默认 False)。

name

动画的名称。

remover

动画结束时 mobject 是否离开场景 (默认 False)。

suspend_mobject_updating

动画期间 mobject 的更新器是否在其下运行(默认 True):它们 持续作用于 mobject,每一帧显示动画应用于其结果。 若为 False,则它们作用于被动画的 mobject 本身。

introducer

动画开始时 mobject 是否加入场景(默认 False); 否则若场景缺少它,play 在其开始时将其带入。

use_override

若某 mobject 的类用另一个动画代替此动画播放,是否如此执行 (默认 True)。

还接受 动画关键字。

源码

manimgx\animation\timeline.py

def __init__(
    self,
    mobject: M | None,
    **options: Unpack[AnimationOptions],
) -> None:
    o = animation_defaults(type(self)) | options
    self.run_time = o.get("run_time", 1.0)
    self.rate_func = o.get("rate_func", smooth)
    self.reverse_rate_function = o.get("reverse_rate_function", False)
    self.name = o.get("name")
    self.remover = o.get("remover", False)
    self.introducer = o.get("introducer", False)
    self.suspend_mobject_updating = o.get("suspend_mobject_updating", True)
    self.lag_ratio = o.get("lag_ratio", 0.0)
    self.use_override = o.get("use_override", True)
    self.frames: list[Mobject] = []  # the keyframes, as derived (`derive`)
    self._model: M | None = None
    self._scene: Scene | None = None  # the scene it plays in (`_setup_scene`)
    self._mobject: M = (
        mobject if mobject is not None else Mobject()  # pyright: ignore[reportAttributeAccessIssue]  # ty: ignore[invalid-assignment]  # none: an Animation[Mobject]
    )

defaults

此类默认设置的选项,仅包含其相对于基类所更改的内容 (它们沿类层次结构向下级联)。

run_time

动画播放时长,以秒为单位;永不为负。

animation.run_time
源码

manimgx\animation\timeline.py

def run_time(self) -> float:
    """动画播放时长,以秒为单位;永不为负。"""
    return self._run_time

mobject

动画所更改的 mobject。

animation.mobject
源码

manimgx\animation\timeline.py

def mobject(self) -> M:
    """动画所更改的 mobject。"""
    return self._mobject

interpolate_mobject

在动画的某一进度设置整个 mobject。

默认情况下,它通过 interpolate_keyframes 将每个部分设置为其自身的进度 (get_sub_alpha:由 lag_ratio 交错,由速率函数缓急)。 重写它以一次性设置整个 mobject,并自行应用 self.rate_func(alpha)。

animation.interpolate_mobject(alpha)
alpha

动画的进度,从 0 到 1,尚未缓急。

源码

manimgx\animation\timeline.py

def interpolate_mobject(self, alpha: float) -> None:
    """在动画的某一进度设置整个 mobject。

    默认情况下,它通过 `interpolate_keyframes` 将每个部分设置为其自身的进度
    (`get_sub_alpha`:由 `lag_ratio` 交错,由速率函数缓急)。
    重写它以一次性设置整个 mobject,并自行应用 `self.rate_func(alpha)`。

    Args:
        alpha: 动画的进度,从 0 到 1,尚未缓急。
    """
    families = list(self.get_all_families_zipped())
    for i, (submobject, *keys) in enumerate(families):
        self.interpolate_keyframes(
            submobject, keys, self.get_sub_alpha(alpha, i, len(families))
        )