ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Manim next_to 用法:标签不跟着物体移动?add_updater 和 VGroup 两种改法(0.21.0 实测)

Manim next_to 用法:标签不跟着物体移动?add_updater 和 VGroup 两种改法(0.21.0 实测) next_to是 Manim 里最常用的相对定位方法label.next_to(tri, RIGHT, buff0.3)把标签摆到三角形右边 0.3 的位置。但它是一次性的只在调用的那一行算一次坐标不会建立「一直在右边」的关系。所以之后三角形一动标签就留在原地。要让标签跟着走有两种改法add_updater每帧重新next_to一次或者把两者装进VGroup一起动。本文代码和坐标数字都在 Manim Community 0.21.02026 年的最新版本上实测过。Manim 是 3Blue1Brown 作者开源的数学动画引擎用 Python 描述画面里有什么、怎么动由它逐帧渲染成视频没接触过的可以先看这篇介绍。下面三段完整代码可以直接贴进极坐标⋅XYZ 的工作区点运行里面装的也是 Manim 0.21.0本机不用装 Python 和 LaTeX。先把问题跑出来一个三角形右边用next_to摆一个 △ABC 的标签然后把三角形往左挪 5 个单位from manim import * class LabelLeftBehind(Scene): def construct(self): tri Polygon([-2, -2, 0], [0, 2, 0], [3, 0, 0], colorBLUE) tri.set_fill(BLUE, 0.5).scale(0.5).move_to(RIGHT * 3) label MathTex(r\triangle ABC, colorYELLOW) label.next_to(tri, RIGHT, buff0.3) self.add(tri, label) self.wait(0.5) self.play(tri.animate.shift(LEFT * 5), run_time2) self.wait()三角形走了标签没动。我们把坐标打印出来看过移动前三角形右边缘在 x 4.25标签左边缘在 x 4.55中间正好隔着buff0.3。移动后三角形右边缘到了 x -0.75标签左边缘还是 4.55两者隔了 5.3 个单位。next_to 那一行到底做了什么label.next_to(tri, RIGHT, buff0.3)执行时Manim 做了三件事取tri外接框右边缘的中点取label外接框左边缘的中点然后把label平移让这两个点在水平方向上相距 0.3。算完就是一次普通的平移label身上只留下了新坐标。tri这个参照物没有被存到任何地方Manim 里也没有「约束」这种东西在后台盯着。所以这行代码的效果和你手算出坐标再写label.move_to([5.33, 0, 0])没有区别只是省了你算的那一步。align_to、to_edge、to_corner、move_to(另一个物体)都是同一个脾气摆的是调用那一刻的位置。网上不少教程的示例里物体动了标签也跟着动看起来像是自动的。翻代码会发现那是在物体挪到新位置之后又调了一次next_to或者干脆每帧都在调。改法一挂一个 updater每帧重新贴一次updater 是挂在物体上的一个函数动画播放期间 Manim 每渲染一帧之前都会调它一遍。把next_to放进去标签每一帧都按三角形的最新位置重新摆from manim import * class LabelFollows(Scene): def construct(self): tri Polygon([-2, -2, 0], [0, 2, 0], [3, 0, 0], colorBLUE) tri.set_fill(BLUE, 0.5).scale(0.5).move_to(RIGHT * 3) label MathTex(r\triangle ABC, colorYELLOW) label.next_to(tri, RIGHT, buff0.3) label.add_updater(lambda m: m.next_to(tri, RIGHT, buff0.3)) self.add(tri, label) self.wait(0.5) self.play(tri.animate.shift(LEFT * 5), run_time2) self.play(tri.animate.scale(1.6), run_time1.5) self.play(Rotate(tri, PI / 2), run_time1.5) label.clear_updaters() self.play(tri.animate.shift(UP * 1.5)) self.wait()比上一段只多了add_updater那一行。lambda m: ...里的m就是label自己Manim 调用时会传进来。这段后面故意多做了几个动作。三角形放大 1.6 倍、再转 90°标签始终贴在它右边 0.3 的位置自己的大小没变。因为next_to每帧重新读的是三角形外接框的右边缘三角形变大、变形、转向外接框跟着变标签也就跟着让位。最后label.clear_updaters()把 updater 摘掉之后三角形往上走标签又不跟了。做动画时经常需要这样前半段跟着到某个时刻松手让标签留在原地或者单独飞去别处。前面那行label.next_to(...)不要删。add_updater挂上去的时候默认不会先执行一次而且紧跟着的self.wait(0.5)也不会触发它wait期间只有带dt参数的 updater写成lambda m, dt: ...的那种才会被调用像这里lambda m: ...这样不带dt的Manim 认为画面是静止的直接跳过。我们试过把那行删掉标签在开头的半秒里一直待在画面正中央等三角形开始动才跳到它旁边。不想写两遍的话可以用label.add_updater(..., call_updaterTrue)挂上的同时立刻执行一次。改法二装进 VGroup一起动如果标签和图形从头到尾都是一体的不需要中途分开更省事的办法是打包from manim import * class GroupMove(Scene): def construct(self): tri Polygon([-2, -2, 0], [0, 2, 0], [3, 0, 0], colorBLUE) tri.set_fill(BLUE, 0.5).scale(0.5).move_to(RIGHT * 3) label MathTex(r\triangle ABC, colorYELLOW) label.next_to(tri, RIGHT, buff0.3) group VGroup(tri, label) self.add(group) self.wait(0.5) self.play(group.animate.shift(LEFT * 5), run_time2) self.play(group.animate.scale(1.6), run_time1.5) self.wait()注意动画的对象换成了group。平移时两者一起走间距保持 0.3。放大就能看出它和改法一的差别了。对group放大 1.6 倍标签也跟着大了 1.6 倍间距从 0.3 变成 0.48。整组是当一张图在缩放里面的相对位置等比例变。所以怎么选看你要的是哪种「跟着」updaterVGroup平移跟着走跟着走图形放大标签大小不变间距不变标签一起放大间距一起放大图形旋转标签不转贴在新外接框旁边标签一起转中途分开clear_updaters()改回对单个物体做动画每帧开销多调一次函数没有给动点标字母、给会伸缩的线段标长度一般用 updater。一个带文字的图标、一个整体移动的小组件用VGroup。常见写错的地方在循环里写 lambda所有标签都跟着最后一个点这个我们自己也踩过for dot, label in zip(dots, labels): label.add_updater(lambda m: m.next_to(dot, UP))动画一播三个标签全叠到最后一个点上面。原因在 Python不在 Manimlambda 里的dot是等到被调用时才去取值的那时循环早跑完了dot已经是最后一个。用默认参数把当前这个dot留住就好for dot, label in zip(dots, labels): label.add_updater(lambda m, ddot: m.next_to(d, UP))挂了 updater 之后还想手动挪标签label.shift(UP)或者self.play(label.animate.shift(UP))都留不住下一帧 updater 又把它贴回三角形旁边。要挪就先clear_updaters()或者改 updater 里的方向和buff。只动了一次却挂了 updater如果三角形只在某一步挪一下之后就不动了不必上 updater在同一个play里让标签也走过去就行self.play( tri.animate.shift(LEFT * 5), label.animate.shift(LEFT * 5), )常见追问FAQQalways_redraw和这里的add_updater有什么区别Aalways_redraw每一帧把物体重新造一遍适合形状本身要变的东西比如连接两个动点的线段、会伸缩的花括号。标签的形状没变只是换位置用add_updater加next_to就够了不用每帧重新排一次公式。Qupdater 会拖慢渲染吗A一个next_to的计算量很小几十个标签都感觉不出来。慢的是在 updater 里每帧新建MathTex这类重对象。Qself.add之前挂 updater 和之后挂有区别吗A先后顺序没有影响。但物体必须在场景里updater 才会被调用。只挂了 updater 却没add的物体位置不会变。Q我想让标签一直在点的右上方而且离得稍远一点A把方向换成URbuff调大m.next_to(dot, UR, buff0.2)。方向常量可以随便换UP、DL都行。这个知识点在教程《布局上· 描述关系不算坐标》的最后一节有视频讲解旁边的代码可以边看边改updater 的完整用法在《Updater》那一课。来源极坐标⋅XYZ · jizuobiao.xyz · 更新于 2026-10-03 · 基于 Manim Community 0.21.0
返回列表