150 lines
4.7 KiB
Python
150 lines
4.7 KiB
Python
|
from manim import *
|
|||
|
|
|||
|
|
|||
|
class ParabolaLesson(Scene):
|
|||
|
# 坐标常量定义
|
|||
|
LEFT_MARGIN = 3.2
|
|||
|
AXIS_CENTER = LEFT * LEFT_MARGIN
|
|||
|
TITLE_POS = UP * 3.2
|
|||
|
FORMULA_POS = UP * 2.2
|
|||
|
SLIDER_POS = UP * 1.2
|
|||
|
GRAPH_POS = LEFT * LEFT_MARGIN
|
|||
|
|
|||
|
def construct(self):
|
|||
|
self._intro()
|
|||
|
self._discovery()
|
|||
|
self._proof()
|
|||
|
self._practice()
|
|||
|
|
|||
|
def _intro(self):
|
|||
|
# 创建坐标轴
|
|||
|
axes = Axes(
|
|||
|
x_range=[-3, 3, 1],
|
|||
|
y_range=[0, 8, 2],
|
|||
|
axis_config={"color": BLUE},
|
|||
|
tips=False
|
|||
|
).shift(self.GRAPH_POS)
|
|||
|
|
|||
|
# 初始曲线 y=x²
|
|||
|
curve = axes.plot(lambda x: x ** 2, color=YELLOW)
|
|||
|
|
|||
|
# 标题和公式
|
|||
|
title = Tex("$a$是正数,开口向上", color=GREEN).to_edge(self.TITLE_POS)
|
|||
|
formula = MathTex("y = x^2", color=RED).to_edge(self.FORMULA_POS)
|
|||
|
|
|||
|
# 动画序列
|
|||
|
self.play(Create(axes), run_time=1.5)
|
|||
|
self.play(Create(curve), Write(formula), run_time=2)
|
|||
|
self.play(Write(title), run_time=1.5)
|
|||
|
self.wait(1)
|
|||
|
|
|||
|
# 保存对象
|
|||
|
self.axes = axes
|
|||
|
self.curve = curve
|
|||
|
self.formula = formula
|
|||
|
self.title = title
|
|||
|
|
|||
|
def _discovery(self):
|
|||
|
# 创建滑杆数值显示
|
|||
|
a_value = DecimalNumber(1.0, num_decimal_places=1)
|
|||
|
a_text = Tex("$a = $").next_to(a_value, LEFT)
|
|||
|
a_display = VGroup(a_text, a_value).to_edge(self.SLIDER_POS)
|
|||
|
|
|||
|
# 更新公式为 y=ax²
|
|||
|
new_formula = MathTex("y = a x^2", color=RED).to_edge(self.FORMULA_POS)
|
|||
|
self.play(Transform(self.formula, new_formula), FadeIn(a_display))
|
|||
|
|
|||
|
# 创建滑杆
|
|||
|
slider = NumberLine(x_range=[0.5, 2.5], length=4, include_numbers=True)
|
|||
|
slider.to_edge(self.SLIDER_POS).shift(DOWN * 0.6)
|
|||
|
dot = Dot(color=RED).move_to(slider.n2p(1))
|
|||
|
|
|||
|
# 添加滑杆动画
|
|||
|
self.play(Create(slider), Create(dot))
|
|||
|
|
|||
|
# 定义曲线更新函数
|
|||
|
def update_curve(mob):
|
|||
|
a = a_value.get_value()
|
|||
|
new_curve = self.axes.plot(lambda x: a * x ** 2, color=YELLOW)
|
|||
|
mob.become(new_curve)
|
|||
|
|
|||
|
# 设置数值更新器
|
|||
|
self.curve.add_updater(update_curve)
|
|||
|
|
|||
|
# 参数变化动画序列
|
|||
|
a_values = [0.5, 1.0, 2.0]
|
|||
|
for a in a_values:
|
|||
|
self.play(
|
|||
|
a_value.animate.set_value(a),
|
|||
|
dot.animate.move_to(slider.n2p(a)),
|
|||
|
run_time=3
|
|||
|
)
|
|||
|
self.wait(0.5)
|
|||
|
|
|||
|
# 移除更新器
|
|||
|
self.curve.remove_updater(update_curve)
|
|||
|
|
|||
|
# 保持5秒静止帧
|
|||
|
self.wait(5)
|
|||
|
|
|||
|
def _proof(self):
|
|||
|
# 更新标题
|
|||
|
new_title = Tex("$a$是负数,开口向下", color=GREEN).to_edge(self.TITLE_POS)
|
|||
|
self.play(Transform(self.title, new_title))
|
|||
|
|
|||
|
# 更新公式
|
|||
|
new_formula = MathTex("y = a x^2", color=RED).to_edge(self.FORMULA_POS)
|
|||
|
self.play(Transform(self.formula, new_formula))
|
|||
|
|
|||
|
# 创建新的滑杆数值显示
|
|||
|
a_value = DecimalNumber(-0.5, num_decimal_places=1)
|
|||
|
a_text = Tex("$a = $").next_to(a_value, LEFT)
|
|||
|
a_display = VGroup(a_text, a_value).to_edge(self.SLIDER_POS)
|
|||
|
|
|||
|
# 创建新滑杆
|
|||
|
slider = NumberLine(x_range=[-2.5, -0.5], length=4, include_numbers=True)
|
|||
|
slider.to_edge(self.SLIDER_POS).shift(DOWN * 0.6)
|
|||
|
dot = Dot(color=RED).move_to(slider.n2p(-0.5))
|
|||
|
|
|||
|
# 添加滑杆动画
|
|||
|
self.play(FadeIn(a_display), Create(slider), Create(dot))
|
|||
|
|
|||
|
# 定义曲线更新函数
|
|||
|
def update_curve(mob):
|
|||
|
a = a_value.get_value()
|
|||
|
new_curve = self.axes.plot(lambda x: a * x ** 2, color=YELLOW)
|
|||
|
mob.become(new_curve)
|
|||
|
|
|||
|
# 设置数值更新器
|
|||
|
self.curve.add_updater(update_curve)
|
|||
|
|
|||
|
# 参数变化动画序列
|
|||
|
a_values = [-0.5, -1.0, -2.0]
|
|||
|
for a in a_values:
|
|||
|
self.play(
|
|||
|
a_value.animate.set_value(a),
|
|||
|
dot.animate.move_to(slider.n2p(a)),
|
|||
|
run_time=3
|
|||
|
)
|
|||
|
self.wait(0.5)
|
|||
|
|
|||
|
# 移除更新器
|
|||
|
self.curve.remove_updater(update_curve)
|
|||
|
|
|||
|
# 保持5秒静止帧
|
|||
|
self.wait(5)
|
|||
|
|
|||
|
def _practice(self):
|
|||
|
# 练习环节留空
|
|||
|
pass
|
|||
|
|
|||
|
|
|||
|
if __name__ == "__main__":
|
|||
|
# 全局指定 ctex 模板(一次性)
|
|||
|
config.tex_template = TexTemplateLibrary.ctex
|
|||
|
# 使用临时配置渲染场景(配置只在with块内有效)
|
|||
|
with tempconfig({"preview": True, "quality": "high_quality"}):
|
|||
|
# 实例化场景类
|
|||
|
scene = ParabolaLesson()
|
|||
|
# 执行渲染流程(包含文件生成和预览)
|
|||
|
scene.render()
|