1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
| from manim import * import numpy as np
config.background_color = BLACK config.frame_width = 9 config.frame_height = 12 config.pixel_width = 1080 config.pixel_height = 1440
class RadialDotsAnimation(Scene): def construct(self): # 小球数量 num_dots = 48 text_num_dots = Text(f"Number of Dots: {num_dots}").scale(0.5).to_corner(UL) self.play(Write(text_num_dots))
# 最大半径 max_radius = 2 # 小球颜色列表 colors = [ RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE, PINK, TEAL, MAROON, GOLD, DARK_BLUE, LIGHT_GRAY, RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE, PINK, TEAL, MAROON, GOLD, DARK_BLUE, LIGHT_GRAY, RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE, PINK, TEAL, MAROON, GOLD, DARK_BLUE, LIGHT_GRAY, RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE, PINK, TEAL, MAROON, GOLD, DARK_BLUE, LIGHT_GRAY ] # 创建小球和它们的径向直线 dots = [] lines = [] for i in range(num_dots): # 计算每个小球的角度(均匀分布) angle = i * PI / num_dots
# 创建径向直线(从中心到边缘) line = Line( max_radius * np.array([-2*np.cos(angle), -2*np.sin(angle), 0]), max_radius * np.array([2*np.cos(angle), 2*np.sin(angle), 0]), color=GRAY, stroke_opacity=1 ) lines.append(line) # 小球初始位置(在直线右端点) initial_pos = line.point_from_proportion(0.5 + 0.5 * np.sin(TAU - angle)) dot = Dot(point=initial_pos, color=colors[i], radius=0.1) dots.append(dot) # 先画出所有径向直线 self.play( LaggedStart( *[Create(line) for line in lines], lag_ratio=0.03, run_time=1.5 ) ) # 显示小球 self.play( LaggedStart( *[GrowFromCenter(dot) for dot in dots], lag_ratio=0.03, run_time=1.5 ) ) self.wait(0.5) # 让小球沿径向直线运动,同时整体形成旋转滚动效果 total_cycles = 2 # 总共完成4个周期 animation_time = 6 # 动画总时间 # 创建每个小球的动画 dot_anims = [] for i, (dot, line) in enumerate(zip(dots, lines)): # 计算每个小球的相位差,实现旋转效果 phase = i * PI / num_dots def update_dot(dot, alpha, line=line, phase=phase): # 使用正弦函数计算位置比例,实现往复运动 # 同时添加相位差,使整体产生旋转效果(alpha(0->1)) pos_ratio = 0.5 + 0.5 * np.sin(alpha * total_cycles * TAU - phase) new_pos = line.point_from_proportion(pos_ratio) dot.move_to(new_pos) dot_anims.append( UpdateFromAlphaFunc( dot, update_dot, run_time=animation_time, rate_func=linear ) ) # 播放动画 - 使用LaggedStart让小球依次开始运动 # lag_ratio控制每个小球开始运动的延迟时间 self.play( LaggedStart( *dot_anims, lag_ratio= 0, # 调整这个值可以改变延迟时间 run_time=animation_time ) ) # 结束时的淡出效果 self.play( LaggedStart( *[FadeOut(dot) for dot in dots], *[FadeOut(line) for line in lines], lag_ratio=0.03, run_time=1.5 ) )
# 运行动画 if __name__ == "__main__": scene = RadialDotsAnimation(preview=True)
|