视频效果
代码
from manim import *
class Sq(Scene):
def construct(self):
# 文本与公式展示
text = Text("可视化平方差公式", font="KaiTi", font_size=80)
math_tex = Tex(r"$a^2 - b^2=(a + b)(a - b)$", font_size=50, color=RED)
text.set_color_by_gradient(YELLOW, GREEN, BLUE, PURPLE)
self.play(Write(text))
self.wait(0.5)
self.play(text.animate.shift(LEFT * 2).scale(0.5))
self.wait(0.5)
self.play(Write(math_tex.shift(RIGHT * 3)))
self.play(FadeOut(text), math_tex.animate.shift(UP * 3 + LEFT * 3))
self.wait(0.5)
# 第一个正方形 (a^2)
a_start_point = LEFT * 2 + UP * 1
a_end_point = RIGHT * 2 + UP * 1
base_line = Line(a_start_point, a_end_point, color=BLUE)
a = Tex(r"$a$", font_size=50, color=RED)
self.play(Create(base_line), Write(a.shift(UP * 1.5)))
self.wait(0.5)
square = Square(side_length=4, color=BLUE, fill_opacity=0.5)
square.move_to(DOWN * 1)
self.play(Create(square), FadeOut(base_line))
self.wait(0.5)
goup = VGroup(square, a)
self.play(goup.animate.shift(LEFT * 2))
# 第二个正方形 (b^2)
b_start_point = RIGHT * 1 + UP * 1
b_end_point = RIGHT * 4 + UP * 1
b_base_line = Line(b_start_point, b_end_point, color=YELLOW)
b = Tex(r"$b$", font_size=50, color=GREEN)
self.play(Create(b_base_line), Write(b.shift(UP * 1.5 + RIGHT * 2.5)))
self.wait(0.5)
square_b = Square(side_length=3, color=YELLOW, fill_opacity=0.5)
square_b.move_to(DOWN * 0.5 + RIGHT * 2.5)
self.play(Create(square_b), FadeOut(b_base_line), b.animate.shift(RIGHT * 2 + DOWN * 1.5))
self.wait(0.5)
gurop_b = VGroup(square_b, b)
self.play(gurop_b.animate.shift(LEFT * 5))
self.wait(0.5)
# 交集区域,闪烁动画
# 计算并显示交集区域
overlap = Intersection(square, square_b,color = RED, fill_opacity=0.8)
self.add(overlap)
self.wait(0.5)
# 添加闪烁动画
self.play(overlap.animate.scale(1.1))
self.play(FadeOut(square_b),overlap.animate.scale(10/11),Flash(overlap, color=PURPLE, flash_radius=0.5))
# 非交集区域
non_overlap_a = Difference(square, overlap, color=PURPLE, fill_opacity=0.5)
self.play(Create(non_overlap_a))
# 平移非公共部分到与下面矩形同一水平线
self.play(non_overlap_a.animate.shift(RIGHT * 5))
self.wait(0.5)
self.play(FadeOut(square,overlap),non_overlap_a.animate.move_to([0,0,0]))
# 添加虚线分割
dashed_line = DashedLine(
start=non_overlap_a.get_top()+DOWN*3+RIGHT*1,
end=non_overlap_a.get_top()+DOWN*3+RIGHT*2,
color=YELLOW,
dash_length=0.2
)
self.play(Create(dashed_line))
self.wait(0.5)
k_f= UP*2+RIGHT*1
k_e = DOWN*1+RIGHT*1
l = Line(k_f, k_e).set_stroke(opacity=0)
self.add(l)
l_brace = Brace(l, LEFT)
one_brace = Brace(non_overlap_a, DOWN)
two_brace = Brace(dashed_line,UP)
RIGHT_brace = Brace(non_overlap_a, RIGHT)
# 创建两个副本
a1 = a.copy()
a2 = a.copy()
self.play(
ReplacementTransform(a.copy(), a1),
ReplacementTransform(a.copy(), a2),
FadeOut(a)
)
# 创建两个副本
b1 = b.copy()
b2 = b.copy()
self.play(
ReplacementTransform(b.copy(), b1),
ReplacementTransform(b.copy(), b2),
FadeOut(b)
)
l_weizhi = l.get_top()+DOWN*1.5+LEFT*1
a1_weizhi = one_brace.get_bottom()+DOWN*0.5
a2_weizhi = RIGHT_brace.get_bottom()+RIGHT*0.5+2*UP
b_weizhi = two_brace.get_top()+UP*0.5
a_b = Tex(r"$a-b$", font_size=40, color=YELLOW).move_to(b_weizhi)
# 添加括号
self.play(
Create(one_brace), Create(two_brace), Create(RIGHT_brace),Create(l_brace),
a1.animate.move_to(a1_weizhi),
a2.animate.move_to(a2_weizhi),
Transform(b1,a_b),
b2.animate.move_to(l_weizhi)
)
self.wait(0.5)
# 创建下方水平矩形
horizontal_rect = Rectangle(width=4, height=1, color=PURPLE, fill_opacity=0)
horizontal_rect.move_to(DOWN * 1.5) # 设置位置
self.add(horizontal_rect)
# 创建上方竖直矩形
vertical_rect = Rectangle(width=1, height=3, color=PURPLE, fill_opacity=0)
vertical_rect.move_to(UP * 0.5 + RIGHT * 1.5) # 设置位置
self.add(vertical_rect)
self.wait(0.5)
# 旋转竖直矩形并水平对齐
self.play(
FadeOut(l_brace,one_brace,two_brace,RIGHT_brace,a1,a2,b1,b2,a_b,l,dashed_line,non_overlap_a),
vertical_rect.animate.rotate(-PI / 2).next_to(horizontal_rect, RIGHT, buff=0)
)
self.wait(0.5)
g = VGroup(horizontal_rect, vertical_rect)
self.play(g.animate.move_to([0,0,0]))
shang = Brace(g,UP)
xia = Brace(g,LEFT)
self.play(Create(shang), Create(xia))
math1 = math_tex.copy()
math2 = math_tex.copy()
self.play(
ReplacementTransform(math_tex.copy(), math1),
ReplacementTransform(math_tex.copy(), math2),
)
self.wait(0.25)
math3 = Tex(r"$a + b$", font_size=50, color=RED)
math4 = Tex(r"$a - b$", font_size=50, color=RED)
math3_weizhi = shang.get_bottom()+UP*0.5
math4_weizhi = xia.get_top()+DOWN*0.5+LEFT*1
self.play(Create(math1),Create(math2),
Transform(math1,math3.move_to(math3_weizhi)),Transform(math2,math4.move_to(math4_weizhi)))
self.play(FadeOut(shang,xia,math1,math2,math3,math4,g),
math_tex.animate.move_to([0,0,0]).scale(2))
self.wait(1)
函数使用汇总
方法/函数 | 所属类别 | 功能/描述 |
---|---|---|
Scene | 场景类 | 自定义场景类的基类,所有动画均需在继承自 Scene 的类中实现,如本例 class Sq(Scene) . |
Text(...) | 文字与公式 | 用于添加普通文本,可指定字体(font )、大小(font_size )、颜色等。 |
Tex(r"公式") | 文字与公式 | 用于添加带 LaTeX 数学公式的文本,支持数学排版。 |
set_color_by_gradient(...) | 文字与公式 | 给对象(如文字)设置指定的渐变颜色,可在多个颜色之间进行过渡。 |
Square(...) | 几何对象 | 创建正方形,可指定边长(side_length )、颜色、填充透明度(fill_opacity )等。 |
Rectangle(...) | 几何对象 | 创建矩形,可指定宽、高、颜色、填充等。 |
Line(start, end, color=) | 几何对象 | 创建线段,起点与终点分别为 start 、end ,并可设置颜色等。 |
DashedLine(...) | 几何对象 | 创建虚线段,可设置虚线长度(dash_length )等参数。 |
Intersection(obj1, obj2, ...) | 布尔运算 | 计算多个图形对象的交集区域,返回一个新对象。 |
Difference(obj1, obj2, ...) | 布尔运算 | 计算两个图形之间的差集区域,返回一个新对象。 |
VGroup(obj1, obj2, ...) | 组合对象 | 将多个对象组合成一个群组,以便整体移动、缩放、旋转等。 |
Brace(mobject, direction) | 辅助标注 | 在指定对象(mobject )附近生成“括号”形注释,可配合 get_top() / get_bottom() 等方法精确定位文字。 |
动画方法 | 动画类 | |
Write(mobject) | 动画方法 | 以“写字”效果显示文本或公式。 |
Create(mobject) | 动画方法 | 以绘制的方式显示线段、路径或图形。 |
FadeOut(mobject) | 动画方法 | 让指定对象渐隐,并在动画结束后从场景中移除。 |
ReplacementTransform(objA, objB) | 动画方法 | 将对象 objA 转换为对象 objB ,常用来替换文字、图形或使对象平滑过渡到另一种形态。 |
Flash(mobject, ...) | 动画方法 | 在指定对象上显示闪烁特效,可通过 color 、flash_radius 、num_lines 等参数调整闪光颜色、半径、线段数量等。 |
animate | 动画方法 | 一种链式写法,允许对对象进行如 move_to() 、shift() 、scale() 、rotate() 等变换动画。 |
shift(direction_vector) | 变换/移动 | 将对象平移指定的向量,如 LEFT*2 、UP*3 等。 |
move_to(position_vector) | 变换/移动 | 让对象移动到给定坐标位置。 |
scale(factor) | 变换/移动 | 对对象进行缩放,可放大或缩小。 |
rotate(angle) | 变换/移动 | 使对象绕自身中心旋转一定角度(弧度制),如 -PI/2 表示逆时针旋转 -90°。 |
next_to(mobject, direction, buff=...) | 变换/移动 | 令对象相对于另一个对象在指定方向紧挨着放置,可指定间距 buff 。 |
wait(seconds=...) | 定时 | 暂停场景指定时间,让画面保持不变。 |
位置/坐标获取 | 位置与坐标 | 下面这些方法通常用于获取对象在场景中的特定坐标点。 |
get_top() | 位置与坐标 | 获取对象顶部中心点的坐标。 |
get_bottom() | 位置与坐标 | 获取对象底部中心点的坐标。 |
get_center() | 位置与坐标 | 获取对象的几何中心点坐标。 |
表格中各方法的使用要点
下面对表格中出现的主要方法或函数做简要说明,便于快速上手:
- Scene 类
- 所有自定义动画类都要继承自
Scene
,并在construct()
方法中添加要显示的动画、图形、文字等。
- 所有自定义动画类都要继承自
- Text / Tex
Text("普通文本")
:在屏幕上显示普通文字,可指定font
、font_size
等。Tex(r"$a^2 - b^2$")
:显示 LaTeX 数学公式,还可以指定color
、font_size
等。
- set_color_by_gradient(…)
- 典型用法:
text.set_color_by_gradient(YELLOW, GREEN, BLUE)
- 能让文字在多个颜色间产生渐变效果。
- 典型用法:
- Square / Rectangle / Line / DashedLine
- 创建基本图形对象: Square(side_length=4, color=BLUE, fill_opacity=0.5)
Rectangle(width=4, height=2, color=RED)
Line(LEFT, RIGHT, color=GREEN)
DashedLine(ORIGIN, 3*RIGHT, dash_length=0.2) - 可根据需要指定颜色、填充透明度、虚线长度等参数。
- 创建基本图形对象: Square(side_length=4, color=BLUE, fill_opacity=0.5)
- Intersection / Difference
Intersection(obj1, obj2, color=...)
: 计算obj1
和obj2
的交集。Difference(obj1, obj2, color=...)
: 计算两个图形的差集。
- VGroup
- 将多个对象用
VGroup
组合在一起,便于统一移动、缩放: group = VGroup(obj1, obj2)
group.shift(RIGHT*2)
- 将多个对象用
- Brace
- 对一个对象加上大括号注释,比如: brace = Brace(obj, DOWN)
text_label = brace.get_text(“说明文字”)
- 对一个对象加上大括号注释,比如: brace = Brace(obj, DOWN)
- 动画方法
- 需要用
self.play(...)
来执行:Write(mobject)
: 文字或公式写入动画。Create(mobject)
: 线段或图形从无到有的绘制动画。FadeOut(mobject)
: 隐去并移除对象。ReplacementTransform(objA, objB)
: 将objA
变换为objB
。
- 需要用
- Flash
- 在对象上显示闪光效果: self.play(
Flash(
mobject,
color=YELLOW,
flash_radius=0.5,
num_lines=10,
run_time=1
)
) - 可用参数
color
,flash_radius
,line_length
,num_lines
,run_time
等调节闪光效果。
- 在对象上显示闪光效果: self.play(
- animate
- 链式变换写法,让对象在动画中做某些平移、旋转、缩放等: square.animate.shift(LEFT*2).rotate(PI/4).scale(1.5)
- 常配合
self.play(...)
使用: self.play(square.animate.shift(RIGHT*2))
- shift / move_to / rotate / scale
shift(LEFT*2)
: 整体向左移动 2 个单位。move_to([x, y, 0])
: 移动到指定坐标点。rotate(PI/2)
: 以对象中心为圆心旋转 90°。scale(1.2)
: 按 1.2 的比例放大。
- 位置坐标方法(get_top / get_bottom / get_center 等)
- 获取对象在场景中的特定位置,以便对齐或放置其他对象: top_coord = obj.get_top()
bottom_coord = obj.get_bottom()
center_coord = obj.get_center()
- 获取对象在场景中的特定位置,以便对齐或放置其他对象: top_coord = obj.get_top()