跳转至

场景

影片代码
import manimgx as m


class SceneHero(m.Scene):
    def construct(self) -> None:
        square = m.Square(color=m.BLUE, fill_opacity=0.5)
        self.add(square)
        self.wait(0.5)
        self.play(square.animate.shift(2 * m.RIGHT), run_time=1)
        self.next_section("turn")
        self.play(square.animate.rotate(m.PI / 4))
        self.remove(square)
        self.wait(0.5)

场景从上到下运行一次其 construct 方法来生成它的视频。construct 中的内容在 play 或 add 将其放入场景之前不会显示,而场景的时间只在 play 或 wait 中移动:视频的每一帧显示场景在其自身精确时刻的状态。

场景还会说话和播放声音:参见 声音 和 语音。

Scene

代码
import manimgx as m


class SceneExample(m.Scene):
    def construct(self) -> None:
        square = m.Square(side_length=3, color=m.BLUE, fill_opacity=0.5)
        self.play(m.Create(square))  # from 0 s to 1 s
        self.wait()  # from 1 s to 2 s
        self.play(square.animate.rotate(m.PI / 4))  # from 2 s to 3 s

一个场景:一段视频,以及其中发生的事情。

从它派生一个类,并在其 construct 方法中写下发生的事情:ManimGX 从上到下运行它一次,render 记录视频。mobject 自场景持有它的那一刻起显示(add 将其放入)。时间 仅在 play 与 wait 中流逝: construct 在二者之间所做的一切都发生在同一时刻。

每一帧在各自的精确时间显示场景,因此场景在任意帧率下都相同:一秒动画 在每秒 60 帧时为 60 帧,在每秒 30 帧时为 30 帧。当 construct 结束时, 最后一帧显示场景结束时的状态,使其最后一个动画的落定被看见。改变场景的 方法返回场景本身,因此其调用可链式串联。

class MyScene(m.Scene):
源码

manimgx\scene.py

def __init__(self) -> None:
    clock.reset()  # a new world: its clock at 0
    self.camera = Camera(three_d=self.three_d)
    """场景的相机:一帧所显示的内容。移动、缩放或为其
    [`frame`][manimgx.Camera.frame] 添加动画以平移与缩放。"""
    self.mobjects: list[Mobject] = []
    """场景持有的 mobject,按绘制顺序排列:每个绘制在先于它的那些之上,
    z-index 相等时如此。[`add`][manimgx.Scene.add] 与
    [`remove`][manimgx.Scene.remove] 改变它。"""
    self.foreground_mobjects: list[Mobject] = []
    """保持在最前的 mobject:绘制在所有其他 mobject 之上,z-index 相等时
    如此(见 [`add_foreground_mobjects`][manimgx.Scene.add_foreground_mobjects])。
    它们也在场景的 [`mobjects`][manimgx.Scene.mobjects] 之中。"""
    self.updaters: list[Callable[[float], object]] = []
    """场景自身的更新器,按其运行顺序排列(见
    [`add_updater`][manimgx.Scene.add_updater])。"""
    self._since: dict[object, Fraction] = {}  # when each scene updater was last run
    self.clock = Fraction(0)
    """场景的时间,精确的:秒的分数(见
    [`time`][manimgx.Scene.time])。"""
    self.frame = 0
    """场景已记录的帧数:下一帧的编号,该帧显示 `frame / fps` 秒处的世界。"""
    self._records = False  # does anything record the world (`_recording`), this run
    # the play's instants no frame shows, with what each concerns (`_exact`, `_ticks`)
    self._events: dict[Fraction, Concern | None] = {}
    self._playing: list[Mobject] = []  # what the play running acts on (`_running`)
    # while animations begin together (`_together`): what the scene held, by id, and
    # the list of mobjects it was found in (`_introduce`)
    self._beginning = False
    self._holding: tuple[list[Mobject], set[int]] | None = None
    # the play running: its animations may hide parts of the scene (`display_list`)
    self._animation: Animation | None = None
    self.num_plays = 0
    """场景已运行的 play 与 wait 次数。"""
    self.film = Film()
    """场景记录的影片:[`render`][manimgx.Scene.render] 新建一个,
    并返回它。"""

发生什么

construct

描述场景,发生什么以及何时发生:重写它。

render 从上到下运行它一次,影片即为其留下的 内容。它是普通 Python:循环、函数与变量如在任何地方一样工作。

self.construct()
源码

manimgx\scene.py

def construct(self) -> None:
    """描述场景,发生什么以及何时发生:重写它。

    [`render`][manimgx.Scene.render] 从上到下运行它一次,影片即为其留下的
    内容。它是普通 Python:循环、函数与变量如在任何地方一样工作。
    """

setup

准备场景:render 在 construct 之前调用它。

除非被重写,否则它什么也不做:在多个场景共享的内容所派生的类中重写它。

self.setup()
源码

manimgx\scene.py

def setup(self) -> None:
    """准备场景:[`render`][manimgx.Scene.render] 在 `construct` 之前调用它。

    除非被重写,否则它什么也不做:在多个场景共享的内容所派生的类中重写它。
    """

tear_down

结束场景:render 在 construct 之后、 闭合帧之前调用它。

除非被重写,否则它什么也不做。

self.tear_down()
源码

manimgx\scene.py

def tear_down(self) -> None:
    """结束场景:[`render`][manimgx.Scene.render] 在 `construct` 之后、
    闭合帧之前调用它。

    除非被重写,否则它什么也不做。
    """

时间

play

代码
import manimgx as m


class ScenePlayExample(m.Scene):
    def construct(self) -> None:
        colors = (m.BLUE, m.YELLOW, m.GREEN)
        dots = m.VGroup(*(m.Dot(radius=0.3, color=c) for c in colors))
        dots.arrange(m.DOWN, buff=1.5).shift(5 * m.LEFT)
        self.add(dots)
        self.play(  # all three begin now; the play lasts 3 s
            dots[0].animate(run_time=1).shift(10 * m.RIGHT),
            dots[1].animate(run_time=2).shift(10 * m.RIGHT),
            dots[2].animate(run_time=3).shift(10 * m.RIGHT),
            rate_func=m.linear,  # for each of the three
        )

从场景当前时间起,同时播放动画。

每个动画从现在开始,持续其自身的运行时间,在其时间用尽时结束, 无论其他仍在播放的动画:play 持续至最长者结束。然后 construct 在 play 结束的时刻继续。要依次播放动画,或每个比前一个稍晚开始,请播放 Succession 或 LaggedStart。

play 将其动画所改变的内容带入场景(若场景尚未持有),按给定顺序。引入 其 mobject 的动画(Create、FadeIn、…) 在其开始时添加它,替换动画在其结束时添加其转换目标。取出其 mobject 的 动画(FadeOut、…)在其结束时移除它。单独播放的 Wait 即为 wait。

self.play(*animations, **options)
*animations

动画,或其可迭代对象;至少一个。

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\scene.py

def play(self, *animations: Animation, **options: Unpack[TransformOptions]) -> None:
    """从场景当前时间起,同时播放动画。

    每个动画从现在开始,持续其自身的运行时间,在其时间用尽时结束,
    无论其他仍在播放的动画:play 持续至最长者结束。然后 `construct` 在
    play 结束的时刻继续。要依次播放动画,或每个比前一个稍晚开始,请播放
    [`Succession`][manimgx.Succession] 或 [`LaggedStart`][manimgx.LaggedStart]。

    play 将其动画所改变的内容带入场景(若场景尚未持有),按给定顺序。引入
    其 mobject 的动画([`Create`][manimgx.Create]、[`FadeIn`][manimgx.FadeIn]、…)
    在其开始时添加它,替换动画在其结束时添加其转换目标。取出其 mobject 的
    动画([`FadeOut`][manimgx.FadeOut]、…)在其结束时移除它。单独播放的
    [`Wait`][manimgx.Wait] 即为 [`wait`][manimgx.Scene.wait]。

    Args:
        *animations: 动画,或其可迭代对象;至少一个。
        **options: 每个动画的[变换选项][manimgx.animation.transform.TransformOptions]:
            给定的每个选项替换该动画自身的选项。因此 `run_time=2` 将每个
            动画播放 2 秒,`lag_ratio` 错开每个的各部分(
            [`LaggedStart`][manimgx.LaggedStart] 错开各动画)。

    Examples:
        ```python
        import manimgx as m


        class ScenePlayExample(m.Scene):
            def construct(self) -> None:
                colors = (m.BLUE, m.YELLOW, m.GREEN)
                dots = m.VGroup(*(m.Dot(radius=0.3, color=c) for c in colors))
                dots.arrange(m.DOWN, buff=1.5).shift(5 * m.LEFT)
                self.add(dots)
                self.play(  # all three begin now; the play lasts 3 s
                    dots[0].animate(run_time=1).shift(10 * m.RIGHT),
                    dots[1].animate(run_time=2).shift(10 * m.RIGHT),
                    dots[2].animate(run_time=3).shift(10 * m.RIGHT),
                    rate_func=m.linear,  # for each of the three
                )
        ```
    """
    from manimgx.animation.timeline import AnimationGroup, Wait, _flatten, prepare
    from manimgx.animation.transform import Compositor

    anims = [prepare(a) for a in _flatten(animations)]
    if not anims:
        raise ValueError("Called Scene.play with no animations")
    for anim in anims:
        for key, value in options.items():
            if value is not None:
                setattr(anim, key, value)
    start, index, where = self.clock, self.num_plays, _written()
    wait = anims[0] if len(anims) == 1 and isinstance(anims[0], Wait) else None
    self.num_plays += 1
    if wait is not None:
        end = start + wait._duration
        self._run(end, stop=wait.stop_condition, frozen=bool(wait.is_static_wait))
    else:
        anim = (
            anims[0]
            if len(anims) == 1
            else AnimationGroup(
                *anims, group=Group(), suspend_mobject_updating=False
            )
        )
        end = start + anim._duration
        self.compositor, self._animation = Compositor(), anim
        try:
            self._play(anim, start, end)
        finally:
            self.compositor, self._animation = None, None
    self.film.played(Play(index, start, self.clock, where), tuple(anims))

wait

代码
import manimgx as m


class SceneWaitExample(m.Scene):
    def construct(self) -> None:
        square = m.Square(side_length=3, color=m.BLUE, fill_opacity=0.5)
        square.add_updater(lambda mob, dt: mob.rotate(dt * m.PI / 3))
        self.add(square)
        self.wait(2)  # time passes: the updater turns the square
        self.wait(1, frozen_frame=True)  # the picture holds
        self.wait(2)  # it turns on from where it stopped

让时间流逝,不播放任何动画:更新器继续运行。

视频延续 duration 秒,construct 在其结束时继续。带 stop_condition 时,wait 在条件成立的第一帧结束,场景从该帧时间继续。带 frozen_frame 时,画面保持:视频延续 duration,但无任何移动,无更新器运行,基于时间 的更新器在之后如同无时间流逝般继续(见 pause)。

self.wait(duration=DEFAULT_WAIT_TIME, stop_condition=None, frozen_frame=None)
duration

持续时长,以秒为单位。

stop_condition

一个无参函数,在每帧绘制后检查:wait 在其返回 True 的 第一帧结束。None:wait 持续其全部时长。

frozen_frame

画面是否在世界静止时保持;不能与 stop_condition 组合 (抛出 ValueError)。None 或 False:时间运行。

源码

manimgx\scene.py

def wait(
    self,
    duration: float = DEFAULT_WAIT_TIME,
    stop_condition: Callable[[], bool] | None = None,
    frozen_frame: bool | None = None,
) -> None:
    """让时间流逝,不播放任何动画:更新器继续运行。

    视频延续 `duration` 秒,`construct` 在其结束时继续。带 `stop_condition`
    时,wait 在条件成立的第一帧结束,场景从该帧时间继续。带 `frozen_frame`
    时,画面保持:视频延续 `duration`,但无任何移动,无更新器运行,基于时间
    的更新器在之后如同无时间流逝般继续(见 [`pause`][manimgx.Scene.pause])。

    Args:
        duration: 持续时长,以秒为单位。
        stop_condition: 一个无参函数,在每帧绘制后检查:wait 在其返回 True 的
            第一帧结束。None:wait 持续其全部时长。
        frozen_frame: 画面是否在世界静止时保持;不能与 `stop_condition` 组合
            (抛出 ValueError)。None 或 False:时间运行。

    Examples:
        ```python
        import manimgx as m


        class SceneWaitExample(m.Scene):
            def construct(self) -> None:
                square = m.Square(side_length=3, color=m.BLUE, fill_opacity=0.5)
                square.add_updater(lambda mob, dt: mob.rotate(dt * m.PI / 3))
                self.add(square)
                self.wait(2)  # time passes: the updater turns the square
                self.wait(1, frozen_frame=True)  # the picture holds
                self.wait(2)  # it turns on from where it stopped
        ```
    """
    from manimgx.animation.timeline import Wait

    self.play(
        Wait(
            run_time=duration,
            stop_condition=stop_condition,
            frozen_frame=frozen_frame,
        )
    )

pause

在世界静止时保持画面:一个带 frozen_frame 的 wait。

视频延续 duration;无更新器运行,基于时间的更新器在之后如同无时间 流逝般继续。

self.pause(duration=DEFAULT_WAIT_TIME)
duration

持续时长,以秒为单位。

源码

manimgx\scene.py

def pause(self, duration: float = DEFAULT_WAIT_TIME) -> None:
    """在世界静止时保持画面:一个带 `frozen_frame` 的
    [`wait`][manimgx.Scene.wait]。

    视频延续 `duration`;无更新器运行,基于时间的更新器在之后如同无时间
    流逝般继续。

    Args:
        duration: 持续时长,以秒为单位。
    """
    self.wait(duration, frozen_frame=True)

wait_until

让时间流逝直到条件成立:一个在 stop_condition 返回 True 的第一帧 结束、或在 max_time 秒之后结束的 wait。

self.wait_until(stop_condition, max_time=60)
stop_condition

一个无参函数,在每帧绘制后检查。

max_time

最长等待时间,以秒为单位。

源码

manimgx\scene.py

def wait_until(
    self, stop_condition: Callable[[], bool], max_time: float = 60
) -> None:
    """让时间流逝直到条件成立:一个在 `stop_condition` 返回 True 的第一帧
    结束、或在 `max_time` 秒之后结束的 [`wait`][manimgx.Scene.wait]。

    Args:
        stop_condition: 一个无参函数,在每帧绘制后检查。
        max_time: 最长等待时间,以秒为单位。
    """
    self.wait(max_time, stop_condition=stop_condition)

time

场景的时间,以秒为单位。

在 construct 中,场景开始时为 0,每次 play 或 wait 返回时为其结束时刻。 在 play 期间,动画与更新器运行时,它为正在生成的帧的时间。

self.time
源码

manimgx\scene.py

def time(self) -> float:
    """场景的时间,以秒为单位。

    在 `construct` 中,场景开始时为 0,每次 play 或 wait 返回时为其结束时刻。
    在 play 期间,动画与更新器运行时,它为正在生成的帧的时间。
    """
    return float(clock.now)

显示什么

add

代码
import manimgx as m


class SceneAddExample(m.Scene):
    def construct(self) -> None:
        square = m.Square(side_length=3.5, color=m.BLUE, fill_opacity=1)
        circle = m.Circle(radius=1.8, color=m.YELLOW, fill_opacity=1)
        circle.shift(1.8 * m.RIGHT)
        self.add(square, circle)  # the circle, added last, is on top
        self.wait()
        self.add(square)  # adding it again brings it to the front
        self.wait()

从现在起将 mobject 放入场景,置于已持有者之前。

每个绘制在先于它添加的 mobject 之上(z-index 相等时),并在前景 mobject 之下。场景已持有的 mobject 移动到最前。作为场景所持有组的一部分的 mobject 从组的位置中取出:组被拆分,其其他成员各自留在原处(组的自身 更新器不再运行);添加的组从场景持有它们的任何位置取走其成员。所添加 mobject 的更新器从现在起运行:基于时间者的第一个 dt 从其 mobject 加入 场景的时刻起算。

self.add(*mobjects)
*mobjects

mobject,按顺序排列:最后一个绘制在最上层。

源码

manimgx\scene.py

def add(self, *mobjects: Mobject) -> Self:
    """从现在起将 mobject 放入场景,置于已持有者之前。

    每个绘制在先于它添加的 mobject 之上(z-index 相等时),并在前景
    mobject 之下。场景已持有的 mobject 移动到最前。作为场景所持有组的一部分的
    mobject 从组的位置中取出:组被拆分,其其他成员各自留在原处(组的自身
    更新器不再运行);添加的组从场景持有它们的任何位置取走其成员。所添加
    mobject 的更新器从现在起运行:基于时间者的第一个 `dt` 从其 mobject 加入
    场景的时刻起算。

    Args:
        *mobjects: mobject,按顺序排列:最后一个绘制在最上层。

    Examples:
        ```python
        import manimgx as m


        class SceneAddExample(m.Scene):
            def construct(self) -> None:
                square = m.Square(side_length=3.5, color=m.BLUE, fill_opacity=1)
                circle = m.Circle(radius=1.8, color=m.YELLOW, fill_opacity=1)
                circle.shift(1.8 * m.RIGHT)
                self.add(square, circle)  # the circle, added last, is on top
                self.wait()
                self.add(square)  # adding it again brings it to the front
                self.wait()
        ```
    """
    if any(m.updaters for mob in mobjects for m in mob.get_family()):
        present = {id(m) for m in self.get_mobject_family_members()}
        for mob in mobjects:  # joining the world: its updaters are live from now
            for m in mob.get_family():
                if id(m) not in present:
                    m._stamp(clock.now, recursive=False)
    new = remove_list_redundancies([*mobjects, *self.foreground_mobjects])
    self.mobjects = _restructure(self.mobjects, new) + new
    return self

remove

将 mobject 移出场景:它们不再被绘制,其更新器停止。

作为场景所持有组的一部分的 mobject 以同样方式被取出:组被拆分,其其他 成员各自留在场景中。场景未持有的 mobject 被忽略。mobject 自身不被改变: 再次添加它将显示其当时的状态。

self.remove(*mobjects)
*mobjects

要移出的 mobject。

源码

manimgx\scene.py

def remove(self, *mobjects: Mobject) -> Self:
    """将 mobject 移出场景:它们不再被绘制,其更新器停止。

    作为场景所持有组的一部分的 mobject 以同样方式被取出:组被拆分,其其他
    成员各自留在场景中。场景未持有的 mobject 被忽略。mobject 自身不被改变:
    再次添加它将显示其当时的状态。

    Args:
        *mobjects: 要移出的 mobject。
    """
    self.mobjects = _restructure(self.mobjects, mobjects, extract=False)
    self.foreground_mobjects = _restructure(
        self.foreground_mobjects, mobjects, extract=False
    )
    return self

clear

将每个 mobject 移出场景,前景 mobject 亦然;场景自身的更新器保留。

self.clear()
源码

manimgx\scene.py

def clear(self) -> Self:
    """将每个 mobject 移出场景,前景 mobject 亦然;场景自身的更新器保留。
    """
    self.mobjects, self.foreground_mobjects = [], []
    return self

replace

将一个 mobject 放入场景中替换另一个:在另一个被绘制的位置,即便在 组内,组随后持有新的那个。

new 首先被移出其要加入的列表(若已在其中)。 ReplacementTransform 以它结束。场景未 持有的 mobject 抛出 ValueError。

self.replace(old, new)
old

要被替换的 mobject:场景持有的一个,或其一部分。

new

要放入其位置的 mobject。

源码

manimgx\scene.py

def replace(self, old: Mobject, new: Mobject) -> None:
    """将一个 mobject 放入场景中替换另一个:在另一个被绘制的位置,即便在
    组内,组随后持有新的那个。

    `new` 首先被移出其要加入的列表(若已在其中)。
    [`ReplacementTransform`][manimgx.ReplacementTransform] 以它结束。场景未
    持有的 mobject 抛出 ValueError。

    Args:
        old: 要被替换的 mobject:场景持有的一个,或其一部分。
        new: 要放入其位置的 mobject。
    """

    def replace_in(lst: list[Mobject]) -> bool:
        if new in lst:
            lst.remove(new)
        for i, m in enumerate(lst):
            if m is old:
                lst[i] = new
                return True
        return any(replace_in(m.submobjects) for m in lst)

    if not (replace_in(self.mobjects) or replace_in(self.foreground_mobjects)):
        raise ValueError(f"Could not find {old} in scene")
    self._holding = None  # (what it holds changed in place)

bring_to_front

将 mobject 绘制在其他 mobject 之上,但在前景 mobject 之下:等同于 add。

self.bring_to_front(*mobjects)
*mobjects

mobject,按顺序排列:最后一个绘制在最上层。

源码

manimgx\scene.py

def bring_to_front(self, *mobjects: Mobject) -> Self:
    """将 mobject 绘制在其他 mobject 之上,但在前景 mobject 之下:等同于
    [`add`][manimgx.Scene.add]。

    Args:
        *mobjects: mobject,按顺序排列:最后一个绘制在最上层。
    """
    return self.add(*mobjects)

bring_to_back

将 mobject 绘制在所有其他 mobject 之下,z-index 相等时如此:它们移动 到场景 mobject 的起始处,若原在前景中则移出前景。

场景未持有的 mobject 在此添加,位于最底层。

self.bring_to_back(*mobjects)
*mobjects

mobject,按顺序排列:第一个绘制在最底层。

源码

manimgx\scene.py

def bring_to_back(self, *mobjects: Mobject) -> Self:
    """将 mobject 绘制在所有其他 mobject 之下,z-index 相等时如此:它们移动
    到场景 mobject 的起始处,若原在前景中则移出前景。

    场景未持有的 mobject 在此添加,位于最底层。

    Args:
        *mobjects: mobject,按顺序排列:第一个绘制在最底层。
    """
    self.remove(*mobjects)
    self.mobjects = [*mobjects, *self.mobjects]
    return self

add_foreground_mobjects

将 mobject 放入场景并置于最前:绘制在所有其他 mobject 之上,z-index 相等时如此,即便之后添加的 mobject 也如此。

self.add_foreground_mobjects(*mobjects)
*mobjects

mobject,按顺序排列:最后一个绘制在最上层。

源码

manimgx\scene.py

def add_foreground_mobjects(self, *mobjects: Mobject) -> Self:
    """将 mobject 放入场景并置于最前:绘制在所有其他 mobject 之上,z-index
    相等时如此,即便之后添加的 mobject 也如此。

    Args:
        *mobjects: mobject,按顺序排列:最后一个绘制在最上层。
    """
    self.foreground_mobjects = remove_list_redundancies(
        [*self.foreground_mobjects, *mobjects]
    )
    return self.add(*mobjects)

remove_foreground_mobjects

将 mobject 移出最前:它们留在场景中,处于其绘制顺序中的位置, 之后添加的 mobject 绘制在它们之上。

self.remove_foreground_mobjects(*mobjects)
源码

manimgx\scene.py

def remove_foreground_mobjects(self, *mobjects: Mobject) -> Self:
    """将 mobject 移出最前:它们留在场景中,处于其绘制顺序中的位置,
    之后添加的 mobject 绘制在它们之上。
    """
    self.foreground_mobjects = _restructure(self.foreground_mobjects, mobjects)
    return self

mobjects

场景持有的 mobject,按绘制顺序排列:每个绘制在先于它的那些之上, z-index 相等时如此。add 与 remove 改变它。

foreground_mobjects

保持在最前的 mobject:绘制在所有其他 mobject 之上,z-index 相等时 如此(见 add_foreground_mobjects)。 它们也在场景的 mobjects 之中。

场景自身的更新器

add_updater

为场景自身添加一个更新器:一个以流逝时间调用的函数。

它被传入 dt,即自上次运行(或被添加)以来以秒为单位的场景时间, 在场景计算的每个时刻、mobject 的更新器之后调用。它像 mobject 的基于 时间的更新器那样步进:在模拟时钟上 (config.simulation_rate 每秒 tick 数,以及每次 play 与 wait 的结束),除非它是 flow,后者在每帧运行。其返回值被忽略。

self.add_updater(func)
func

该更新器:一个单参数函数,名为 dt。

源码

manimgx\scene.py

def add_updater(self, func: Callable[[float], object]) -> None:
    """为场景自身添加一个更新器:一个以流逝时间调用的函数。

    它被传入 `dt`,即自上次运行(或被添加)以来以秒为单位的场景时间,
    在场景计算的每个时刻、mobject 的更新器之后调用。它像 mobject 的基于
    时间的更新器那样步进:在模拟时钟上
    ([`config.simulation_rate`][manimgx.config.Config.simulation_rate]
    每秒 tick 数,以及每次 play 与 wait 的结束),除非它是
    [flow][manimgx.mobject.flow],后者在每帧运行。其返回值被忽略。

    Args:
        func: 该更新器:一个单参数函数,名为 `dt`。
    """
    self.updaters.append(func)
    self._since[func] = clock.now

remove_updater

从场景移除一个更新器,每次添加都移除。

这也取消当前更新中尚未运行的调用。

self.remove_updater(func)
func

该更新器。

源码

manimgx\scene.py

def remove_updater(self, func: Callable[[float], object]) -> None:
    """从场景移除一个更新器,每次添加都移除。

    这也取消当前更新中尚未运行的调用。

    Args:
        func: 该更新器。
    """
    self.updaters = [f for f in self.updaters if f is not func]
    if func not in self.updaters:
        self._since.pop(func, None)

段落

next_section

在此处开始影片的一个分段:当影片被演示时,即一张幻灯片。

影片是分段的序列,每个持续到下一个开始(第一个随影片开始)。演示时 (manimgx present),影片播放一个分段并按其类型在其结束时停止,直到 演示者继续、自动继续或反复播放直到演示者继续。分段在一帧处开始,该帧 画面为演示所停留:若场景时间落在两帧之间,世界保持静止直到下一帧。 渲染时,影片仅依次播放其各分段。

self.next_section(name='unnamed', section_type='default.normal', skip_animations=False, *, notes='')
name

分段的名称。

section_type

演示如何播放此处开始的分段: "default.normal"(或 "presentation.normal")在其结束时停止; "presentation.skip" 自动继续;"presentation.loop" 反复播放 直到演示者继续;"presentation.complete_loop" 亦然,但先完成 当前一轮。

skip_animations

为兼容 Manim 而接受;被忽略。

notes

演示者在该分段期间朗读的内容。

源码

manimgx\scene.py

def next_section(
    self,
    name: str = "unnamed",
    section_type: SectionType = "default.normal",
    skip_animations: bool = False,
    *,
    notes: str = "",
) -> None:
    """在此处开始影片的一个分段:当影片被演示时,即一张幻灯片。

    影片是分段的序列,每个持续到下一个开始(第一个随影片开始)。演示时
    (`manimgx present`),影片播放一个分段并按其类型在其结束时停止,直到
    演示者继续、自动继续或反复播放直到演示者继续。分段在一帧处开始,该帧
    画面为演示所停留:若场景时间落在两帧之间,世界保持静止直到下一帧。
    渲染时,影片仅依次播放其各分段。

    Args:
        name: 分段的名称。
        section_type: 演示如何播放此处开始的分段:
            `"default.normal"`(或 `"presentation.normal"`)在其结束时停止;
            `"presentation.skip"` 自动继续;`"presentation.loop"` 反复播放
            直到演示者继续;`"presentation.complete_loop"` 亦然,但先完成
            当前一轮。
        skip_animations: 为兼容 Manim 而接受;被忽略。
        notes: 演示者在该分段期间朗读的内容。
    """
    fps = self._fps()
    at = Fraction(self.frame) / fps
    if at != self.clock:  # to its frame, the world held still
        self._run(at, frozen=True)
    self.film.section(name, self.clock, section_type, notes)

它的摄像机与它的影片

camera

场景的相机:一帧所显示的内容。移动、缩放或为其 frame 添加动画以平移与缩放。

frame

场景已记录的帧数:下一帧的编号,该帧显示 frame / fps 秒处的世界。

three_d

场景的相机是否以三维方式观察:为 ThreeDScene 时为 True。

film

场景记录的影片:render 新建一个, 并返回它。

num_plays

场景已运行的 play 与 wait 次数。