'Asynchronously run different animations in manim
I'm trying run essentially two animations (ref. following code):
class RelTrain(Scene):
def construct(self):
train = Rectangle(height=1, width=4)
train2 = Rectangle(height=2, width=2)
train.move_to(np.array([-10,0,0]))
train2.move_to(np.array([0,0,0]))
self.add(train, train2)
self.play(
train.move_to, np.array([10,0,0]),
train2.move_to, np.array([15,0,0]),
run_time=18,
rate_func=linear,
)
self.wait()
Essentially two rectangles are moving, but I do not want them to begin movement simultaneously. I want train
to start moving, and after 2 seconds (train
would still be moving at this point since run_time=18
), I want train2
to pop up on the screen and begin its motion. I'm not sure how this is done and would appreciate any help.
Solution 1:[1]
After playing for a while, I've figured how to do this with ManimCE (v0.3.0). This is not very well documented yet, but essentially you can use mobject updaters. I'm not sure if this is the best way to do this (it seems to me that is too much verbose and low level), but it works:
Code
import numpy as np
from manim import *
class DeplayedTrains(Scene):
def construct(self):
# create both trains
trains = (
Rectangle(height=1, width=4),
Rectangle(height=2, width=2),
)
# indicate start and end points
start_points_X, end_points_X = ((-5, 0), (5, 5))
# compute movement distances for both trains
distances = (
(end_points_X[0] - start_points_X[0]),
(end_points_X[1] - start_points_X[1]),
)
# place trains at start points and add to the scene
for train, start_point in zip(trains, start_points_X):
train.move_to(np.array([start_point, 0, 0]))
self.add(train)
# deifine durations of movements for both trains, get FPS from config
durations, fps = ((5, 3), config["frame_rate"])
# create updaters
updaters = (
# add to the current position in X the difference for each frame,
# given the distance and duration defined
lambda mobj, dt: mobj.set_x(mobj.get_x() + (distances[0] / fps / durations[0])),
lambda mobj, dt: mobj.set_x(mobj.get_x() + (distances[1] / fps / durations[1])),
)
# add updaters to trains objects, movement begins
trains[0].add_updater(updaters[0])
# wait 2 seconds
self.wait(2)
# start the movement of the second train and wait 3 seconds
trains[1].add_updater(updaters[1])
self.wait(3)
# remove the updaters
trains[0].clear_updaters() # you can also call trains[0].remove_updater(updaters[0])
trains[1].clear_updaters()
Output
Solution 2:[2]
For those looking to making animations start at different times while still partially temporally overlapping, take a look at LaggedStart
and similar things:
https://docs.manim.community/en/stable/reference/manim.animation.composition.html
Unfortunately they are not documented, but it took me a while to realize they even existed.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Emerson Peters |