zeno_paradox.py
1# -*- coding: utf-8 -*-2from manim import *3import numpy as np4 5class ZenoParadox(Scene):6 def construct(self):7 # 设置默认字体8 Text.set_default(font="SimSun")9 10 # 标题11 title = Text("芝诺悖论:阿基里斯追乌龟").scale(0.8)12 title.to_edge(UP, buff=0.5)13 self.play(Write(title))14 self.wait(1)15 16 # 初始条件说明17 conditions = VGroup(18 Text("初始条件:").scale(0.6),19 VGroup(20 Text("速度:", color=RED).scale(0.4),21 MathTex("v_A = 2").scale(0.5)22 ).arrange(RIGHT, buff=0.2),23 VGroup(24 Text("速度:", color=GREEN).scale(0.4),25 MathTex("v_T = 1").scale(0.5)26 ).arrange(RIGHT, buff=0.2)27 ).arrange(DOWN, aligned_edge=LEFT, buff=0.2)28 conditions.next_to(title, DOWN, buff=0.5)29 30 self.play(Write(conditions))31 self.wait(2)32 33 # 创建数轴34 number_line = NumberLine(35 x_range=[0, 5, 1], # 范围改为0到536 length=12, # 调整长度37 include_numbers=True,38 include_tip=True39 )40 number_line.shift(DOWN)41 42 # 创建角色43 achilles = Text("A", color=RED).scale(0.6)44 turtle = Text("T", color=GREEN).scale(0.6)45 46 # 设置初始位置47 achilles.move_to(number_line.number_to_point(0) + UP * 0.5)48 turtle.move_to(number_line.number_to_point(2) + UP * 0.5)49 50 # 修改初始位置标注,添加时间51 initial_brace = Brace(52 Line(53 number_line.number_to_point(0),54 number_line.number_to_point(2)55 ),56 UP57 )58 initial_labels = VGroup(59 MathTex("s_1 = 2").scale(0.4),60 MathTex("t_1 = 1").scale(0.4) # 添加时间标注61 ).arrange(DOWN, buff=0.1)62 initial_labels.next_to(initial_brace, UP, buff=0.1)63 64 self.play(65 Create(number_line),66 FadeIn(achilles),67 FadeIn(turtle),68 Create(initial_brace),69 Write(initial_labels)70 )71 72 # 修改追赶过程的路程和时间定义73 steps = [74 {"s": 2, "t": 1}, # s₁=2 (第一段2米,用1秒)75 {"s": 1, "t": r"\frac{1}{2}"}, # s₂=1 (第二段1米,用0.5秒)76 {"s": r"\frac{1}{2}", "t": r"\frac{1}{4}"}, # s₃=1/2 (第三段0.5米,用0.25秒)77 {"s": r"\frac{1}{4}", "t": r"\frac{1}{8}"} # s₄=1/4 (第四段0.25米,用0.125秒)78 ]79 80 braces_and_labels = VGroup(initial_brace, initial_labels)81 achilles_pos = 082 turtle_pos = 283 84 for i, step in enumerate(steps[1:], start=1): # 从第二步开始85 # 移动阿基里斯86 achilles_pos = turtle_pos87 self.play(88 achilles.animate.move_to(number_line.number_to_point(achilles_pos) + UP * 0.5)89 )90 91 # 移动乌龟92 if i == 1:93 turtle_pos += 1 # 第二步乌龟移动1米94 elif i == 2:95 turtle_pos += 0.5 # 第三步乌龟移动0.5米96 elif i == 3:97 turtle_pos += 0.25 # 第四步乌龟移动0.25米98 99 self.play(100 turtle.animate.move_to(number_line.number_to_point(turtle_pos) + UP * 0.5)101 )102 103 # 修改标注部分104 new_brace = Brace(105 Line(106 number_line.number_to_point(achilles_pos),107 number_line.number_to_point(turtle_pos)108 ),109 UP,110 buff=0.1 * (i + 1)111 )112 113 # 根据步骤调整标注位置,显示距离和时间114 if i == len(steps) - 1: # 最后一步115 new_labels = VGroup(116 MathTex(f"s_{i+1} = {step['s']}").scale(0.4),117 MathTex(f"t_{i+1} = {step['t']}").scale(0.4)118 ).arrange(DOWN, buff=0.1)119 new_labels.next_to(new_brace, UP, buff=0.1).shift(RIGHT * 0.5)120 else:121 new_labels = VGroup(122 MathTex(f"s_{i+1} = {step['s']}").scale(0.4),123 MathTex(f"t_{i+1} = {step['t']}").scale(0.4)124 ).arrange(DOWN, buff=0.1)125 new_labels.next_to(new_brace, UP, buff=0.1)126 127 braces_and_labels.add(new_brace, new_labels)128 129 self.play(130 Create(new_brace),131 Write(new_labels)132 )133 134 self.wait(1)135 136 self.wait(2)137 138 # 修改底部累加信息139 total_info = VGroup(140 # 路程累加141 MathTex(142 r"s_{\text{total}} = s_1 + s_2 + s_3 + s_4 + \cdots",143 r"= 2 + 1 + \frac{1}{2} + \frac{1}{4} + \cdots"144 ).scale(0.4),145 # 时间累加146 MathTex(147 r"t_{\text{total}} = t_1 + t_2 + t_3 + t_4 + \cdots",148 r"= 1 + \frac{1}{2} + \frac{1}{4} + \frac{1}{8} + \cdots"149 ).scale(0.4)150 ).arrange(DOWN, buff=0.3)151 152 # 将累加信息放在数轴下方153 total_info.next_to(number_line, DOWN, buff=1)154 155 # 修改古代表述部分156 ancient_text = VGroup(157 Text("古曰:", color=YELLOW).scale(0.5),158 Text("一尺之捶,日取其半,万世不竭", color=YELLOW).scale(0.5),159 VGroup(160 Text("即:", color=YELLOW).scale(0.4),161 MathTex(162 r"1 + \frac{1}{2} + \frac{1}{4} + \frac{1}{8} + \cdots < 2"163 ).scale(0.4)164 ).arrange(RIGHT, buff=0.2)165 ).arrange(DOWN, buff=0.3)166 167 # 将古代表述放在数轴下方,在累加信息之后168 ancient_text.next_to(total_info, DOWN, buff=0.5)169 170 # 添加说明文字171 info_text = Text(172 "此过程将无限进行下去...", 173 color=YELLOW174 ).scale(0.4)175 info_text.next_to(ancient_text, DOWN, buff=0.3)176 177 self.play(Write(total_info))178 self.play(Write(ancient_text))179 self.play(Write(info_text))180 self.wait(2)181 182def main():183 scene = ZenoParadox()184 scene.render()185 186if __name__ == "__main__":187 main() 讲解
这个视频围绕「芝诺悖论」展开。画面把问题、图像和公式放在同一条理解路径中,让抽象关系先被看见。
开头先建立问题背景和主要对象,让观察从标题、坐标或第一组关系进入。
画面中出现的文字「芝诺悖论:阿基里斯追乌龟」给出视觉入口。随后画面通过对象创建、移动、淡入淡出和高亮,把抽象命题拆成可以跟随的步骤。
随后出现更具体的图像或公式提示,动画会把局部对象和整体结论联系起来。这里可以重点观察变量、曲线、区域或向量如何随镜头推进而变化。
核心公式可以写成:
这类公式可以和画面中的符号一一对应。
观察路径
观察路径可以分三步:先锁定「芝诺悖论」中的核心对象,尤其留意芝诺悖论、无穷级数、数列收敛之间的联系;再跟随画面中变量、图像或向量的变化;最后回到公式或结论,判断局部变化如何支撑整体关系。
本页可以从芝诺悖论、无穷级数、数列收敛、极限过程这些概念进入,继续沿相邻问题观察同一类数学结构。