189 lines
5.5 KiB
Python
189 lines
5.5 KiB
Python
from manim import *
|
||
|
||
|
||
class ParabolaLesson(Scene):
|
||
# 坐标常量定义
|
||
LEFT_MARGIN = 3.2
|
||
AXIS_RANGE = [-4, 4, -1, 3]
|
||
|
||
# 颜色定义
|
||
BG_COLOR = "#F5F5F5"
|
||
CURVE_COLOR = "#00BFFF"
|
||
FOCUS_COLOR = "#FF4500"
|
||
DIRECTRIX_COLOR = "#AAAAAA"
|
||
|
||
def construct(self):
|
||
self.camera.background_color = self.BG_COLOR
|
||
self._intro()
|
||
self._discovery()
|
||
self._proof()
|
||
self._practice()
|
||
|
||
def _intro(self):
|
||
# 创建坐标系
|
||
axes = Axes(
|
||
x_range=[-4, 4, 1],
|
||
y_range=[-1, 3, 1],
|
||
axis_config={"color": BLACK},
|
||
tips=False
|
||
)
|
||
axes_labels = axes.get_axis_labels(x_label="x", y_label="y")
|
||
|
||
# 初始抛物线 (a=1)
|
||
a_value = ValueTracker(1)
|
||
parabola = always_redraw(lambda: axes.plot(
|
||
lambda x: a_value.get_value() * x ** 2,
|
||
color=self.CURVE_COLOR
|
||
))
|
||
|
||
# 添加所有元素
|
||
self.add(axes, axes_labels, parabola)
|
||
|
||
def _discovery(self):
|
||
# 标题
|
||
title = Tex("$a$是正数,开口向上", color=BLUE).to_edge(UP)
|
||
|
||
# 公式
|
||
formula = MathTex("y = a x^2", color=BLACK).next_to(title, DOWN)
|
||
|
||
# 滑杆
|
||
slider = NumberLine(
|
||
x_range=[0, 2, 0.5],
|
||
length=4,
|
||
color=BLACK,
|
||
include_numbers=True
|
||
).to_edge(DOWN)
|
||
slider_label = Tex("$a$值:", color=BLACK).next_to(slider, LEFT)
|
||
|
||
# 滑杆指示器
|
||
dot = Dot(color=RED).move_to(slider.n2p(1))
|
||
a_value = ValueTracker(1)
|
||
dot.add_updater(lambda d: d.move_to(slider.n2p(
|
||
a_value.get_value()
|
||
)))
|
||
a_text = always_redraw(lambda: DecimalNumber(
|
||
a_value.get_value(),
|
||
color=RED
|
||
).next_to(dot, UP))
|
||
|
||
# 添加元素
|
||
self.play(
|
||
Write(title),
|
||
Write(formula),
|
||
Create(slider),
|
||
Write(slider_label)
|
||
)
|
||
self.add(dot, a_text)
|
||
|
||
# 动画:a值变化 (0.5 -> 1 -> 2)
|
||
self.play(
|
||
a_value.animate.set_value(0.5),
|
||
run_time=5,
|
||
rate_func=rate_functions.ease_in_out_sine
|
||
)
|
||
self.play(
|
||
a_value.animate.set_value(1),
|
||
run_time=5,
|
||
rate_func=rate_functions.ease_in_out_sine
|
||
)
|
||
self.play(
|
||
a_value.animate.set_value(2),
|
||
run_time=5,
|
||
rate_func=rate_functions.ease_in_out_sine
|
||
)
|
||
|
||
# 5秒静止帧
|
||
self.wait(5)
|
||
|
||
def _proof(self):
|
||
# 更新标题
|
||
new_title = Tex("$a$是负数,开口向下", color=BLUE).to_edge(UP)
|
||
|
||
# 滑杆范围变为负数
|
||
slider = NumberLine(
|
||
x_range=[-2, 0, 0.5],
|
||
length=4,
|
||
color=BLACK,
|
||
include_numbers=True
|
||
).to_edge(DOWN)
|
||
slider_label = Tex("$a$值:", color=BLACK).next_to(slider, LEFT)
|
||
|
||
# 更新滑杆指示器
|
||
a_value = ValueTracker(-1)
|
||
dot = Dot(color=RED).move_to(slider.n2p(-1))
|
||
dot.add_updater(lambda d: d.move_to(slider.n2p(
|
||
a_value.get_value()
|
||
)))
|
||
a_text = always_redraw(lambda: DecimalNumber(
|
||
a_value.get_value(),
|
||
color=RED
|
||
).next_to(dot, UP))
|
||
|
||
# 更新公式
|
||
formula = MathTex("y = a x^2", color=BLACK).next_to(new_title, DOWN)
|
||
|
||
# 焦点和准线
|
||
focus = always_redraw(lambda: Dot(
|
||
color=self.FOCUS_COLOR
|
||
).move_to([0, 1 / (4 * a_value.get_value()), 0]))
|
||
|
||
directrix = always_redraw(lambda: DashedLine(
|
||
start=[-4, -1 / (4 * a_value.get_value()), 0],
|
||
end=[4, -1 / (4 * a_value.get_value()), 0],
|
||
color=self.DIRECTRIX_COLOR
|
||
))
|
||
|
||
# 切换元素
|
||
self.play(
|
||
Transform(self.mobjects[0], new_title),
|
||
Transform(self.mobjects[1], formula),
|
||
Transform(self.mobjects[2], slider),
|
||
Transform(self.mobjects[3], slider_label)
|
||
)
|
||
self.add(focus, directrix)
|
||
|
||
# 动画:a值变化 (-0.5 -> -1 -> -2)
|
||
self.play(
|
||
a_value.animate.set_value(-0.5),
|
||
run_time=5,
|
||
rate_func=rate_functions.ease_in_out_sine
|
||
)
|
||
self.play(
|
||
a_value.animate.set_value(-1),
|
||
run_time=5,
|
||
rate_func=rate_functions.ease_in_out_sine
|
||
)
|
||
self.play(
|
||
a_value.animate.set_value(-2),
|
||
run_time=5,
|
||
rate_func=rate_functions.ease_in_out_sine
|
||
)
|
||
|
||
# 5秒静止帧
|
||
self.wait(5)
|
||
|
||
def _practice(self):
|
||
# 添加练习题文本
|
||
practice = Tex(
|
||
"思考题:当$a=-1$时,\\\\焦点和准线在哪里?",
|
||
color=BLUE
|
||
).scale(0.8).to_edge(DOWN)
|
||
|
||
# 显示练习题
|
||
self.play(Write(practice))
|
||
self.wait(5)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
# 全局指定 ctex 模板(一次性)
|
||
config.tex_template = TexTemplateLibrary.ctex
|
||
# 使用临时配置渲染场景(配置只在with块内有效)
|
||
with tempconfig({
|
||
"quality": "low_quality",
|
||
"preview": True,
|
||
"output_file": "ParabolaLesson"
|
||
}):
|
||
# 实例化场景类
|
||
scene = ParabolaLesson()
|
||
# 执行渲染流程(包含文件生成和预览)
|
||
scene.render() |