英文:
Problem in manim animation only last 2 seconds
问题
类 PendBall(Scene):
def 构造(self):
正方形 = 正方形(边长=1.5, 填充不透明度=1, 填充颜色=蓝色E)
线 = 线(原点, [0, 4, 0], 缓冲=0)
子弹 = 圆(半径=0.2, 填充颜色=红色, 填充不透明度=1)
子弹.移动(6*左)
self.flag = False
def 更新子弹(子弹: Mobject, dt):
if 子弹.获取_x() >= 正方形.获取左侧()[0] 或 self.flag:
子弹_速度 = -1
self.flag = True
self.play(旋转(线, 角度=PI/4,
绕点=[0, 4, 0], 运行时间=10),
旋转(正方形, 角度=PI/4, 绕点=[0, 4, 0], 运行时间=10))
else:
子弹_速度 = 1
子弹.移动(np.array([子弹_速度, 0, 0])*dt)
子弹.添加更新器(更新子弹)
self.play(淡入(正方形, 线))
self.play(淡入(子弹))
self.wait(10)
英文:
class PendBall(Scene):
def construct(self):
square = Square(side_length=1.5, fill_opacity=1, fill_color=BLUE_E)
line = Line(ORIGIN, [0, 4, 0], buff=0)
bullet = Circle(radius=0.2, fill_color=RED, fill_opacity=1)
bullet.shift(6*LEFT)
self.flag = False
def updatebullet(bullet: Mobject, dt):
if bullet.get_x() >= square.get_left()[0] or self.flag:
bullet_vel = -1
self.flag = True
self.play(Rotate(line, angle=PI/4,
about_point=[0, 4, 0], run_time=10),
Rotate(square, angle=PI/4, about_point=[0, 4, 0], run_time=10))
else:
bullet_vel = 1
bullet.shift(np.array([bullet_vel, 0, 0])*dt)
bullet.add_updater(updatebullet)
self.play(FadeIn(square, line))
self.play(FadeIn(bullet))
self.wait(10)
the animation only lasts for two seconds
and also
seems like is getting stuck on an infinite loop
when I add the runtimes in the rotation class interpreter get stuck into an infinite loop when I ELIMINATE the runtimes the animation only lasts 2 sec
when trying to add run time to the fadein bullet I get the error ValueError: write to closed file
答案1
得分: 1
在更新器内部无法启动新的 self.play()
动画。
更新器函数会在每帧中被调用,在您的动画中生成每一帧时,也就是说,当您以每秒15帧的速度渲染时,更新器将被调用15次。
如果您在更新器内部启动一个新的10秒长的动画,那将会再次调用更新器150次,每次都会启动一个新的10秒长的动画....
在Discord上寻求有关Manim的问题 - 在那里您将获得快速帮助和许多提示!
https://discord.com/channels/581738731934056449/785271046970278008
英文:
You cannot start a new self.play()
animation inside an updater.
An updater function is called for each frame which is generated in your manimation, i.e. when you render at 15 frames per second, the updater will be called 15 times.
If you now start a new 10 second long animation inside your updater than that would call the updater another 150 times, each time starting a new 10 second long animation....
Come over to Discord with questions on Manim - there you will get fast help and a lot of tips!
https://discord.com/channels/581738731934056449/785271046970278008
答案2
得分: 1
以下是翻译好的部分:
实际问题是你不能在更新器内部调用 self.play()
。但是你有一个很好的小函数,在这里可能会很有用。它叫做 turn_animation_into_updater()
。这个函数可以在更新器内部调用,并创建另一个更新器,播放该动画(与其他动画并行),直到动画达到末尾,在那时辅助更新器被移除。
关于你的代码的其他观察:
- 一旦速度被改为 -1,你就不想把速度重新设置为 1。所以 else 部分可以被移除。
- 你不需要一个标志。你可以测试速度是否为正数。
- 你可以将速度作为子弹对象的一部分进行存储,这样它在更新器调用之间会被保留下来。
- 要使块进行动画,你可能希望使用适当的
rate_func
,当动画接近尾声时,减小它的速度。
有了所有这些想法:
class Test(Scene):
def construct(self):
square = Square(side_length=1.5, fill_opacity=1, fill_color=BLUE_E)
line = Line(ORIGIN, [0, 4, 0], buff=0)
bullet = Circle(radius=0.2, fill_color=RED, fill_opacity=1)
bullet.shift(6*LEFT)
bullet.velocity = 2
ease_out_sine = rate_functions.ease_out_sine
def updatebullet(bullet: Mobject, dt):
if bullet.get_x() >= square.get_left()[0] and bullet.velocity > 0:
bullet.velocity *= -1
turn_animation_into_updater(
Rotate(line, angle=PI/4, about_point=[0, 4, 0],
run_time=5, rate_func=ease_out_sine))
turn_animation_into_updater(
Rotate(square, angle=PI/4, about_point=[0, 4, 0],
run_time=5, rate_func=ease_out_sine))
bullet.shift(np.array([bullet.velocity, 0, 0])*dt)
bullet.add_updater(updatebullet)
square.add_updater(lambda m,dt: None)
line.add_updater(lambda m,dt: None)
self.play(FadeIn(square, line))
self.play(FadeIn(bullet))
self.wait(10)
产生的效果如下:
英文:
The actual problem is that you cannot call self.play()
inside an updater. But you have a little nice function that can be useful here. It is turn_animation_into_updater()
. This one can be called from an updater, and creates another updater which plays that animation (in parallel with others), until the animation reach its end, at which moment the auxiliar updater is removed.
Other observations about your code:
- You dont want to set the velocity back to 1, once it was changed to -1. So the else part can be removed
- You don't need a flag. You can test if the velocity is positive
- You can store the velocity as part of the bullet object, so that it is preserverd between updater calls.
- To animate the block, you may want to use an appropiate
rate_func
which decreases its velocity when the animation is reaching its end.
With all these ideas:
class Test(Scene):
def construct(self):
square = Square(side_length=1.5, fill_opacity=1, fill_color=BLUE_E)
line = Line(ORIGIN, [0, 4, 0], buff=0)
bullet = Circle(radius=0.2, fill_color=RED, fill_opacity=1)
bullet.shift(6*LEFT)
bullet.velocity = 2
ease_out_sine = rate_functions.ease_out_sine
def updatebullet(bullet: Mobject, dt):
if bullet.get_x() >= square.get_left()[0] and bullet.velocity > 0:
bullet.velocity *= -1
turn_animation_into_updater(
Rotate(line, angle=PI/4, about_point=[0, 4, 0],
run_time=5, rate_func=ease_out_sine))
turn_animation_into_updater(
Rotate(square, angle=PI/4, about_point=[0, 4, 0],
run_time=5, rate_func=ease_out_sine))
bullet.shift(np.array([bullet.velocity, 0, 0])*dt)
bullet.add_updater(updatebullet)
square.add_updater(lambda m,dt: None)
line.add_updater(lambda m,dt: None)
self.play(FadeIn(square, line))
self.play(FadeIn(bullet))
self.wait(10)
Which produces:
答案3
得分: 1
以下是代码的中文翻译:
class PendBall(Scene):
def construct(self):
pendulum = VGroup(
Square(side_length=1.5, fill_opacity=1, fill_color=BLUE_E),
Line(ORIGIN, [0, 4, 0], buff=0)
)
pendulum.ang_vel = 0
bullet = Circle(radius=0.2, fill_color=RED, fill_opacity=1)
bullet.shift(6*LEFT)
bullet.vel = 1
def bulletUpdater(mobj,dt):
mobj.shift(mobj.vel * dt * RIGHT)
bullet.add_updater(bulletUpdater)
def pendulumUpdater(mobj, dt):
if bullet.get_x() >= mobj[0].get_left()[0]:
bullet.vel = -1
mobj.ang_vel = 1
if ((mobj[0].get_x()>2) and (mobj.ang_vel > 0)) or ((mobj[0].get_x()<-2) and (mobj.ang_vel < 0)):
mobj.ang_vel *= -1
mobj.rotate(mobj.ang_vel * dt, about_point=mobj[1].get_end())
pendulum.add_updater(pendulumUpdater)
self.play(FadeIn(pendulum))
self.play(FadeIn(bullet))
self.wait(10)
英文:
ok I guess you wanted to achieve something similar to this: (very rough sketch)
class PendBall(Scene):
def construct(self):
pendulum = VGroup(
Square(side_length=1.5, fill_opacity=1, fill_color=BLUE_E),
Line(ORIGIN, [0, 4, 0], buff=0)
)
pendulum.ang_vel = 0
bullet = Circle(radius=0.2, fill_color=RED, fill_opacity=1)
bullet.shift(6*LEFT)
bullet.vel = 1
def bulletUpdater(mobj,dt):
mobj.shift(mobj.vel * dt * RIGHT)
bullet.add_updater(bulletUpdater)
def pendulumUpdater(mobj, dt):
if bullet.get_x() >= mobj[0].get_left()[0]:
bullet.vel = -1
mobj.ang_vel = 1
if ((mobj[0].get_x()>2) and (mobj.ang_vel > 0)) or ((mobj[0].get_x()<-2) and (mobj.ang_vel < 0)):
mobj.ang_vel *= -1
mobj.rotate(mobj.ang_vel * dt, about_point=mobj[1].get_end())
pendulum.add_updater(pendulumUpdater)
self.play(FadeIn(pendulum))
self.play(FadeIn(bullet))
self.wait(10)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论