痛点场景还原
假设做一个最经典的追及动画:甲从原点出发,速度
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 最擅长的事。
- 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,动画就能自适应任意追及条件。
