Animando nuestros Mobjects
¡Uff! Menudo paseo lo de los Mobjects. Vamos ahora a ahora a algo más dinámico: Las animaciones. Aquí también hay mucho que morder, pero empezaremos por lo básico.
Animando propiedades básicas
Sección titulada «Animando propiedades básicas»En Manim las animaciones funcionan recalculando una propiedad de un Mobject de forma que vemos un cambio en la pantalla. Para esto tenemos varias opciones pero la más sencilla consiste en utilizar el método play de la clase Scene junto con el método animate de los Mobjects.
Al hacer esto, Manim recalcula la propiedad para cada fotograma y la muestra en pantalla. Una de las propiedades más sencillas que podemos modificar es la posición. En el apartado de Mobjects hablamos sobre como se pueden usar métodos como shift, move_to o to_edge. Vamos a aplicarlos en un ejemplo.
from manim import *
class PositionAnimationExample(Scene): def construct(self): sq = Square(fill_opacity=1)
self.play( sq.animate.shift(UP) ) self.play( sq.animate.move_to([6,-2,0]) ) self.play( sq.animate.to_edge(LEFT) ) self.play(sq.animate.move_to(ORIGIN))Por supuesto, podemos animar muchas otras propiedades, especialmente las que ya conocemos: tamaño, color, rotación, opacidad, etc.
from manim import *
class PropertiesAnimationExample(Scene): def construct(self): sq = Square().set_opacity(0)
self.play( sq.animate.set_opacity(1) ) self.play( sq.animate.rotate(PI/4, axis=IN) ) self.play( sq.animate.scale(2) ) self.play( sq.animate.set_fill_color(RED) ) self.play( sq.animate.set_stroke_width(30) )Cambiando el ritmo
Sección titulada «Cambiando el ritmo»La animación pinta bien, pero ahora mismo todas las animaciones duran exactamente lo mismo y no hay pausas entre ellas.
Podemos cambiar la duración de las animaciones utilizando el parámetro run_time de la función play.
Para agregar pausas podemos usar el método wait de la clase Scene.
from manim import *
class PausedAnimationExample(Scene): def construct(self): sq = Square().set_opacity(0)
self.play( sq.animate.set_opacity(1) ) # Waits 1 second by default self.wait() self.play( sq.animate.rotate(PI/4, axis=IN), run_time=3 # Set the seconds for the animation to run ) # We can indicate the seconds to pause the animation self.wait(2) self.play( sq.animate.scale(2) ) self.play( sq.animate.set_fill_color(RED) ) self.play( sq.animate.set_stroke_width(30) ) self.wait()He devenido target_mobject, el destructor de mundos
Sección titulada «He devenido target_mobject, el destructor de mundos»Otro método muy interesante de los Mobjects es become. Cuando Manim calcula una animación, lo que suele hacer es una interpolación entre las propiedades del objeto inicial y las propiedades del objeto final. Por ejemplo, cuando hemos aplicado shift al cuadrado de antes, Manim ha generado una copia del cuadrado en la posición final, ha interpolado las propiedades que cambian (en este caso la posición) y ha ido generando copias del cuadro en cada fotograma con las nuevas propiedades dando la ilusión de movimiento.
Este proceso lo podemos aplicar no solo a copias de un Mobject sino también a otros Mobjects con valores totalmente diferentes en sus propiedades mediante el método become.
from manim import *
class BecomeAnimationExample(Scene): def construct(self): sq = Square() circ = Circle() self.play(sq.animate.become(circ), run_time=3) self.wait()Explorando el potencial
Sección titulada «Explorando el potencial»Agrego este punto para que podamos observar el potencial de Manim a la hora de crear animaciones. El siguiente ejemplo incluye cosas que no hemos visto aún pero es demasiado chulo como para dejarlo fuera. Está sacado del tutorial de Manim del canal de YouTube Varniex>.
from manim import *import numpy as npfrom math import cos, sin
class RosePattern(VMobject): def __init__(self, radius=2, k=3, **kwargs): super().__init__(**kwargs) self.radius = radius self.k = k
step_size = 0.05 theta = np.arange(0, TAU + step_size, step_size)
points = [ [ radius * cos(k*t) * cos(t), radius * cos(k*t) * sin(t), 0 ] for t in theta ]
self.set_points_smoothly(points)
class RosePatternExample(Scene): def construct(self):
def update_pattern(pat, dt): pat.k += dt new_pat = RosePattern(k=pat.k, color=MAROON_A) pat.become(new_pat)
rose = RosePattern(k=0) self.add(rose) rose.add_updater(update_pattern)
self.wait(10) rose.remove_updater(update_pattern) self.wait()¡Ejercicios!
Sección titulada «¡Ejercicios!»Ejercicio 1
Sección titulada «Ejercicio 1»Escoge un Mobject cualquiera (incluso de ejemplos anteriores) y haz una animación en la que se cambien su color y su posición a la vez. No secuencialmente.
Solución al ejercicio 1
from manim import *
class AnimationsExerciseOne(Scene): def construct(self): circle = Circle(fill_opacity=1)
self.play( circle.animate.shift(3*UP).set_color(PURPLE), )Ejercicio 2
Sección titulada «Ejercicio 2»Crea una colección de Mobjects como por ejemplo Dot, ordénalos en horizontal y haz que suban secuencialmente y que luego bajen todos a la vez. Puntos extra si agregas una pausa.
Solución al ejercicio 2
from manim import *
class AnimationsExerciseTwo(Scene): def construct(self): DOTS_AMOUNT = 10 dots = VGroup([ Dot(color=random_color()) for _ in range(DOTS_AMOUNT) ]).arrange(RIGHT)
self.add(dots) for dot in dots: self.play(dot.animate.shift(UP))
self.wait()
# Notice how we can animate all at once because they are in a VGroup self.play(dots.animate.shift(DOWN))