Ir al contenido

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.

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.

position_animation_example.py
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.

properties_animation_example.py
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)
)

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.

paused_animation_example.py
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.

become_animation_example.py
from manim import *
class BecomeAnimationExample(Scene):
def construct(self):
sq = Square()
circ = Circle()
self.play(sq.animate.become(circ), run_time=3)
self.wait()

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>.

rose_pattern_example.py
from manim import *
import numpy as np
from 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()

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
animations_ex_1.py
from manim import *
class AnimationsExerciseOne(Scene):
def construct(self):
circle = Circle(fill_opacity=1)
self.play(
circle.animate.shift(3*UP).set_color(PURPLE),
)

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
animations_ex_2.py
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))