使用Manim实现循环闪烁圆点动画遇黑帧问题求助
Manim圆点闪烁动画黑帧问题修复
问题描述
我想用Manim制作一个圆点闪烁动画:圆点瞬间显示后保持可见t_on秒,随后瞬间隐藏并保持不可见t_off秒,循环至总时长t_total结束。但按以下代码生成的动画只有黑帧,没有内容。示例参数:t_on=1.5、t_off=0.5、t_total=6。
错误代码
from manim import * class RecursiveDot(Scene): def construct(self): dot = Dot(color=BLUE, radius=0.2) animation = self.create_animation(dot, 6, 1.5, 0.5) self.play(animation) def create_animation(self, dot, total_duration, visible_duration, invisible_duration): num_cycles = int(total_duration // (visible_duration + invisible_duration)) visible_animation = Create(dot, run_time=0) invisible_animation = Uncreate(dot, run_time=0) animations = [] for _ in range(num_cycles): animations.append(visible_animation) animations.append(Wait(invisible_duration)) animations.append(invisible_animation) animations.append(Wait(visible_duration)) return AnimationGroup(*animations, run_time=total_duration)
生成命令:
manim -p -ql path_to_file.py RecursiveDot
问题原因
- 动画执行逻辑错误:
AnimationGroup是并行执行所有传入的动画和等待动作,导致显示、隐藏、等待同时触发,画面无有效内容。 - 循环顺序颠倒:原代码显示圆点后等待
t_off、隐藏后等待t_on,完全不符合需求逻辑。 - 重复使用动画实例:同一个
Create/Uncreate实例被多次复用,可能引发状态冲突,无法正确触发动画。
修复方案
方案一:直接控制可见性(推荐)
通过修改圆点的visible属性实现瞬间显示/隐藏,逻辑清晰且高效:
from manim import * class RecursiveDot(Scene): def construct(self): dot = Dot(color=BLUE, radius=0.2) self.add(dot) # 将圆点添加到场景 dot.visible = False # 初始状态设为隐藏 t_on = 1.5 t_off = 0.5 t_total = 6 cycle_duration = t_on + t_off num_cycles = int(t_total // cycle_duration) # 执行完整循环 for _ in range(num_cycles): dot.visible = True self.wait(t_on) dot.visible = False self.wait(t_off) # 处理总时长剩余的部分 remaining_time = t_total % cycle_duration if remaining_time > 0: dot.visible = True self.wait(min(remaining_time, t_on)) if remaining_time > t_on: dot.visible = False self.wait(remaining_time - t_on)
方案二:使用Succession串行执行动画
如果坚持用动画类实现,将AnimationGroup替换为Succession(串行执行动画序列),同时修正循环顺序:
from manim import * class RecursiveDot(Scene): def construct(self): dot = Dot(color=BLUE, radius=0.2) t_on = 1.5 t_off = 0.5 t_total = 6 cycle_duration = t_on + t_off num_cycles = int(t_total // cycle_duration) animations = [] for _ in range(num_cycles): # 每次循环创建新的动画实例,避免状态冲突 animations.append(Create(dot, run_time=0)) animations.append(Wait(t_on)) animations.append(Uncreate(dot, run_time=0)) animations.append(Wait(t_off)) # 用Succession按顺序执行所有动画 self.play(Succession(*animations)) # 处理剩余时长 remaining_time = t_total % cycle_duration if remaining_time > 0: self.play(Create(dot, run_time=0)) self.wait(min(remaining_time, t_on)) if remaining_time > t_on: self.play(Uncreate(dot, run_time=0)) self.wait(remaining_time - t_on)
说明
- 方案一直接操作可见性,无需创建动画实例,性能更优,逻辑也更直观。
- 方案二的核心是用
Succession替代AnimationGroup,确保动画按顺序执行,这是解决原代码黑帧问题的关键。 - 两种方案都补充了剩余时长的处理,保证动画严格覆盖
t_total的总时长。
内容的提问来源于stack exchange,提问作者Meysam Sadeghi
相关产品推荐
相关产品推荐

