Problem in manim animation 只有最后2秒。

huangapple go评论88阅读模式
英文:

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

Problem in manim animation 只有最后2秒。

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)

产生的效果如下:

Problem in manim animation 只有最后2秒。

英文:

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:

Problem in manim animation 只有最后2秒。

答案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() &gt;= mobj[0].get_left()[0]:
                bullet.vel = -1
                mobj.ang_vel = 1
            if  ((mobj[0].get_x()&gt;2) and (mobj.ang_vel &gt; 0)) or ((mobj[0].get_x()&lt;-2) and (mobj.ang_vel &lt; 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)        

huangapple
  • 本文由 发表于 2023年5月20日 23:09:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/76295905.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定