痛点场景还原

假设做一个最经典的追及动画:甲从原点出发,速度
v
1

2
;乙从
x

10
处同向出发,速度
v
2

5
,问多久追上。

如果用纯手工方式写 Manim:

class PainfulCatchUp(Scene):
def construct(self):
# 手动列方程并求解
# 设 t 为乙出发后的时间,甲的位置:2*(t+?),乙的位置:10+5*t
# 如果同时出发:2t = 10+5t → t = -10/3 负数无意义
# 改甲先出发2秒:2(t+2) = 10+5t → 2t+4=10+5t → -3t=6 → t=-2 还是负
# 必须反复调整题设,手算满足实际情况的初始条件
# 这里干脆让乙追甲,甲在乙前面:
# 甲在x=10以v=2向前,乙在x=0以v=5同时出发 → 5t = 10+2t → 3t=10 → t=10/3
v1, v2 = 2, 5
t_meet = 10/3 # 手动解出的结果
meet_x = 5 * t_meet # 再手动算相遇位置

# 甲和乙的轨迹只能硬编码 def pos1(t): return 10 + v1 * t def pos2(t): return v2 * t # 然后创建动画……

痛点很明显:

每次改变速度或初始距离,都要重新手写方程、求解、算相遇坐标。
题目条件稍微变化(比如“甲先走1分钟”、“乙在中途休息”),手算的过程就得全部推翻重来。
容易在单位换算、正方向等细节上出错,动画一旦跑起来发现不对,排查起来也费劲。
这些计算本质上就是根据文字描述建立代数方程并求解,正是 SymPy 最擅长的事。

  1. SymPy 解决方案介绍
    SymPy 可以让我们用符号把追及问题“翻译”成方程,然后自动求解。

import sympy as sp

符号定义:t 为乙出发后经过的时间

t = sp.symbols(‘t’, positive=True)
v1, v2 = 2, 5 # 速度
s0 = 10 # 初始距离(甲在乙前面10米)

甲的位置:先出发0秒(即同时出发),位置 = s0 + v1*t

pos1 = s0 + v1 * t

乙的位置:从0开始,位置 = v2*t

pos2 = v2 * t

相遇条件:位置相等

eq = sp.Eq(pos1, pos2)
solution = sp.solve(eq, t)

输出: [10/3]

如果甲先出发 2 秒,方程只需改一下:

t_delay = 2 # 甲早出发2秒
pos1 = s0 + v1 * (t + t_delay) # 甲多走2秒
eq = sp.Eq(pos1, pos2)
solution = sp.solve(eq, t)

输出: [14/3]

无论怎么变化,我们只需要修改符号表达式的构建逻辑,求解交给 solve,相遇坐标直接代入即可。

接下来把这个思想嵌入 Manim,动画就能自适应任意追及条件。