写笔记是为了让自己每天总结自己的学习成果,有自己的一些理解,也希望可以帮助大家,小白一枚,如有不对,请大家指正
一个倒计时动画(这里已经跳过Scene类的学习)(文末有简洁版过程解释)
from manim import *
class Count(Animation):
def __init__(self, number: DecimalNumber, start: float, end: float, **kwargs) -> None:
# Pass number as the mobject of the animation
super().__init__(number, **kwargs)
# Set start and end
self.start = start
self.end = end
def interpolate_mobject(self, alpha: float) -> None:
# Set value of DecimalNumber according to alpha
value = self.start + (alpha * (self.end - self.start))
self.mobject.set_value(value)
class CountingScene(Scene):
def construct(self):
# Create Decimal Number and add it to scene
number = DecimalNumber().set_color(WHITE).scale(5)
# Add an updater to keep the DecimalNumber centered as its value changes
number.add_updater(lambda number: number.move_to(ORIGIN))
self.add(number)
self.wait()
# Play the Count Animation to count from 0 to 100 in 4 seconds
self.play(Count(number, 0, 100), run_time=4, rate_func=linear)
self.wait()
单纯定义scene类也是有动画的,比如Transfrom,但是往往不能满足很多场景,比如你想写一个倒计时,这就像定义函数的理由一样,你需要自己写一个(定义)动画。
class Count(Animation):
定义了一个动画类的子类
def __init__(self, number: DecimalNumber, start: float, end: float, **kwargs) -> None:
这里是构造这个类的方法,number: DecimalNumber就是指你传入的参数number必须是DecimalNumber类的一个实例,请注意: DecimalNumber是manim库中的一个类,已经预定义了,这里与后面的start:float不同,前者传入的是一个实例作为参数,后者就是一个float数据作为参数;**kwargs是指其它参数,啥意思我也不懂。
super().__init__(number, **kwargs)
这里调用了原父类也就是Animation的构造方法,以获取动画类的原属性
self.start = start
self.end = end
这两行确定了类的属性,也就是后面构造的实例都会有这两个属性,这两个属性怎么决定的?你往前看,构造的时候要求输入两个参数,那就是它们。
def interpolate_mobject(self, alpha: float) -> None:
这是动画类最核心最核心的地方——定义插值函数;
因为动画呢,其实是在每一帧都有不同的效果,比如你一个数字的变化,从100变到1,你就得写个函数来让每一帧的数字确定是多少,这个就是插值函数,它的参数就是时间嘛,但是我们这里不是绝对时间,而是一个动画的起点和终点作为衡量标准,这个标准就是
alpha: float
alpha就代表这个动画的时间,起点是0,表示进行了百分之0了,终点是1,表示进行了百分之100;然后后面就开始定义每个进度的时候,对我们的类干的事情。
value = self.start + (alpha * (self.end - self.start))
self.mobject.set_value(value)
这里就是用进度影响变量value,利用mobject.set_value方法更新self的属性“值”
class CountingScene(Scene):
def construct(self):
# Create Decimal Number and add it to scene
number = DecimalNumber().set_color(WHITE).scale(5)
# Add an updater to keep the DecimalNumber centered as its value changes
number.add_updater(lambda number: number.move_to(ORIGIN))
这一段就是Scene类了,也就是生成的视频的画面核心,这里number = DecimalNumber()就是创建实例,但这里的实例还不是一个动画,它等会会作为一个参数被传入Count类,用Count类的方法去构建一个动画类(Animation)实例;本段最后一行是一个位置更新器,用了匿名函数lambda,为了保证这个数字出现在画面中心。接着下面这段就是Scene的展示了:
self.add(number)
self.wait()
# Play the Count Animation to count from 0 to 100 in 4 seconds
self.play(Count(number, 0, 100), run_time=4, rate_func=linear)
self.wait()
这里先把number实例添加到画面了,因为这样才可以用后面Count构造的实例来对它进行“动化”,形成动画,后面就是创建动画实例,Count(number, 0, 100), run_time=4, rate_func=linear,并且play出来。
——————————————————————————————————————————
简洁版:
-
导入 Manim 库:
通过from manim import *
,代码导入了 Manim 库的所有内容。这是开始使用 Manim 制作动画的常规第一步。 -
定义
Count
动画类:
这段代码定义了一个名为Count
的新动画类,它继承自Animation
基类。Count
类能够使得一个DecimalNumber
对象的数值在动画过程中从start
变化到end
。__init__
方法初始化动画,接收一个DecimalNumber
对象以及开始和结束的数值。interpolate_mobject
方法定义了如何根据alpha
(当前动画的进度比例,从0到1)计算当前时刻DecimalNumber
的具体值。
-
定义
CountingScene
场景类:
这个类继承自Scene
,它定义了动画的具体构造逻辑。- 在
construct
方法中:- 首先,创建一个白色、放大5倍的
DecimalNumber
对象,并且有一个更新器(updater),使得这个数字对象始终保持在画面中心。 - 接着,场景中增加了这个
DecimalNumber
对象。 - 接下来,使用
self.wait()
暂停一下,以便于在动画开始前有个静止画面。 - 然后,使用
self.play(Count(...))
播放之前定义的Count
动画,让数字从0数到100,这个过程持续4秒钟,并且数值变化是线性的(rate_func=linear
)。 - 最后,又是一个
self.wait()
暂停,让观众可以在动画结束后还能看到最终的画面。
- 首先,创建一个白色、放大5倍的
- 在
简言之,这段代码的执行结果是:
- 首先,屏幕中央会出现一个大号的白色数字0。
- 随后,这个数字开始平滑地从0增加到100,整个过程线性变化,持续4秒钟。
- 数字到达100后,画面会保持静止,让观众有时间观察最终结果。