mirror of
https://github.com/3b1b/manim.git
synced 2025-11-14 12:27:44 +00:00
PiCreatureScene and TeacherStudentScene refactors
This commit is contained in:
parent
ef47e6e884
commit
899a911e08
20 changed files with 359 additions and 237 deletions
|
|
@ -334,7 +334,6 @@ class AnimationGroup(Animation):
|
|||
for anim in sub_anims:
|
||||
#Use np.divide to that 1./0 = np.inf
|
||||
anim.alpha_multiplier = np.divide(max_run_time, anim.run_time)
|
||||
|
||||
if "run_time" in kwargs:
|
||||
self.run_time = kwargs.pop("run_time")
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ class Transform(Animation):
|
|||
self.path_arc,
|
||||
self.path_arc_axis,
|
||||
)
|
||||
|
||||
def get_all_mobjects(self):
|
||||
return self.mobject, self.starting_mobject, self.target_mobject
|
||||
|
||||
|
|
@ -154,9 +153,6 @@ class FadeIn(Transform):
|
|||
target = mobject.copy()
|
||||
Transform.__init__(self, mobject, target, **kwargs)
|
||||
self.starting_mobject.fade(1)
|
||||
if isinstance(self.starting_mobject, VMobject):
|
||||
self.starting_mobject.set_stroke(width = 0)
|
||||
self.starting_mobject.set_fill(opacity = 0)
|
||||
|
||||
|
||||
class ShimmerIn(DelayByOrder):
|
||||
|
|
|
|||
|
|
@ -63,13 +63,13 @@ class CircleScene(PiCreatureScene):
|
|||
self.radius_brace, self.radius_label
|
||||
)
|
||||
|
||||
self.pi_creature = self.get_pi_creature()
|
||||
self.pi_creature = self.create_pi_creature()
|
||||
if self.include_pi_creature:
|
||||
self.add(self.pi_creature)
|
||||
else:
|
||||
self.pi_creature.set_fill(opacity = 0)
|
||||
|
||||
def get_pi_creature(self):
|
||||
def create_pi_creature(self):
|
||||
return Mortimer().to_corner(DOWN+RIGHT)
|
||||
|
||||
def introduce_circle(self, added_anims = []):
|
||||
|
|
@ -240,17 +240,19 @@ class OpeningQuote(Scene):
|
|||
"highlighted_quote_terms" : {
|
||||
"special case" : BLUE
|
||||
},
|
||||
"author" : "David Hilbert"
|
||||
"author" : "David Hilbert",
|
||||
"fade_in_kwargs" : {
|
||||
"submobject_mode" : "lagged_start",
|
||||
"rate_func" : None,
|
||||
"lag_factor" : 3,
|
||||
"run_time" : 5,
|
||||
},
|
||||
}
|
||||
def construct(self):
|
||||
quote = self.get_quote()
|
||||
author = self.get_author(quote)
|
||||
|
||||
self.play(FadeIn(
|
||||
quote,
|
||||
submobject_mode = "lagged_start",
|
||||
run_time = 4
|
||||
))
|
||||
self.play(FadeIn(quote, **self.fade_in_kwargs))
|
||||
self.dither(2)
|
||||
self.play(Write(author, run_time = 3))
|
||||
self.dither()
|
||||
|
|
@ -322,7 +324,7 @@ class Introduction(TeacherStudentsScene):
|
|||
lambda p : p.change_mode("hooray").look_at(series[1]),
|
||||
pi
|
||||
)
|
||||
for pi in self.get_everyone()
|
||||
for pi in self.get_pi_creatures()
|
||||
]
|
||||
)
|
||||
def homotopy(x, y, z, t):
|
||||
|
|
@ -336,7 +338,7 @@ class Introduction(TeacherStudentsScene):
|
|||
),
|
||||
*[
|
||||
ApplyMethod(pi.look_at, series[-1])
|
||||
for pi in self.get_everyone()
|
||||
for pi in self.get_pi_creatures()
|
||||
],
|
||||
run_time = 5
|
||||
)
|
||||
|
|
@ -345,13 +347,13 @@ class Introduction(TeacherStudentsScene):
|
|||
FadeOut(self.teacher.bubble.content),
|
||||
*[
|
||||
ApplyMethod(pi.change_mode, "happy")
|
||||
for pi in self.get_everyone()
|
||||
for pi in self.get_pi_creatures()
|
||||
]
|
||||
)
|
||||
|
||||
def look_to_center(self):
|
||||
anims = []
|
||||
for pi in self.get_everyone():
|
||||
for pi in self.get_pi_creatures():
|
||||
anims += [
|
||||
pi.change_mode, "pondering",
|
||||
pi.look_at, 2*UP
|
||||
|
|
@ -360,7 +362,7 @@ class Introduction(TeacherStudentsScene):
|
|||
self.random_blink(6)
|
||||
self.play(*[
|
||||
ApplyMethod(pi.change_mode, "happy")
|
||||
for pi in self.get_everyone()
|
||||
for pi in self.get_pi_creatures()
|
||||
])
|
||||
|
||||
def go_through_students(self):
|
||||
|
|
@ -846,7 +848,7 @@ class IntroduceTinyChangeInArea(CircleScene):
|
|||
self.play(FadeIn(rect))
|
||||
self.dither()
|
||||
|
||||
def get_pi_creature(self):
|
||||
def create_pi_creature(self):
|
||||
morty = Mortimer()
|
||||
morty.scale(0.7)
|
||||
morty.to_corner(DOWN+RIGHT)
|
||||
|
|
@ -872,7 +874,7 @@ class BuildToDADR(CircleScene):
|
|||
self.elaborate_on_d()
|
||||
self.not_infinitely_small()
|
||||
|
||||
def get_pi_creature(self):
|
||||
def create_pi_creature(self):
|
||||
morty = Mortimer()
|
||||
morty.flip()
|
||||
morty.to_corner(DOWN+LEFT)
|
||||
|
|
@ -1212,7 +1214,7 @@ class BuildToDADR(CircleScene):
|
|||
self.play(self.pi_creature.change_mode, "guilty")
|
||||
self.dither()
|
||||
|
||||
new_bubble = self.pi_creature.get_bubble("speech")
|
||||
new_bubble = self.pi_creature.get_bubble(SpeechBubble)
|
||||
new_bubble.set_fill(BLACK, opacity = 0.8)
|
||||
new_bubble.write("But it gets \\\\ less wrong!")
|
||||
new_bubble.resize_to_content()
|
||||
|
|
@ -1682,7 +1684,7 @@ class DerivativeAsTangentLine(ZoomedScene):
|
|||
morty = Mortimer()
|
||||
morty.scale(0.7)
|
||||
morty.to_edge(DOWN).shift(2*RIGHT)
|
||||
bubble = morty.get_bubble("speech", height = 2)
|
||||
bubble = morty.get_bubble(SpeechBubble, height = 2)
|
||||
bubble.set_fill(BLACK, opacity = 0.8)
|
||||
bubble.shift(0.5*DOWN)
|
||||
bubble.write("This is the standard view")
|
||||
|
|
@ -1747,7 +1749,7 @@ class IntroduceConcentricRings(CircleScene):
|
|||
self.write_integral()
|
||||
self.ask_about_approx()
|
||||
|
||||
def get_pi_creature(self):
|
||||
def create_pi_creature(self):
|
||||
morty = Mortimer()
|
||||
morty.scale(0.7)
|
||||
morty.to_corner(DOWN+RIGHT)
|
||||
|
|
@ -2306,7 +2308,7 @@ class FundamentalTheorem(CircleScene):
|
|||
self.radius_label,
|
||||
)
|
||||
|
||||
def get_pi_creature(self):
|
||||
def create_pi_creature(self):
|
||||
morty = Mortimer()
|
||||
morty.scale(0.7)
|
||||
morty.to_corner(DOWN+RIGHT)
|
||||
|
|
@ -2481,7 +2483,7 @@ class NameTheFundamentalTheorem(TeacherStudentsScene):
|
|||
Write(abstract),
|
||||
*[
|
||||
ApplyMethod(pi.look_at, symbols)
|
||||
for pi in self.get_everyone()
|
||||
for pi in self.get_pi_creatures()
|
||||
]
|
||||
)
|
||||
self.change_student_modes("pondering", "confused", "erm")
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ class Introduction(TeacherStudentsScene):
|
|||
pi.change_mode, mode,
|
||||
pi.look_at, SPACE_HEIGHT*UP
|
||||
]
|
||||
for pi, mode in zip(self.get_everyone(), [
|
||||
for pi, mode in zip(self.get_pi_creatures(), [
|
||||
"speaking", "pondering", "confused", "confused",
|
||||
])
|
||||
])
|
||||
|
|
|
|||
|
|
@ -1901,8 +1901,8 @@ class OneOverX(PiCreatureScene, GraphScene):
|
|||
|
||||
########
|
||||
|
||||
def get_pi_creature(self):
|
||||
morty = PiCreatureScene.get_pi_creature(self)
|
||||
def create_pi_creature(self):
|
||||
morty = PiCreatureScene.create_pi_creature(self)
|
||||
morty.scale(
|
||||
self.morty_scale_val,
|
||||
about_point = morty.get_corner(DOWN+RIGHT)
|
||||
|
|
@ -2718,7 +2718,7 @@ class NextVideo(TeacherStudentsScene):
|
|||
|
||||
group = VGroup(d_sum, d_product, d_composition)
|
||||
group.arrange_submobjects(RIGHT, buff = 2*LARGE_BUFF)
|
||||
group.next_to(VGroup(*self.get_everyone()), UP, buff = LARGE_BUFF)
|
||||
group.next_to(VGroup(*self.get_pi_creatures()), UP, buff = LARGE_BUFF)
|
||||
|
||||
self.play(
|
||||
FadeIn(
|
||||
|
|
@ -2728,7 +2728,7 @@ class NextVideo(TeacherStudentsScene):
|
|||
),
|
||||
*[
|
||||
ApplyMethod(pi.look_at, next_video)
|
||||
for pi in self.get_everyone()
|
||||
for pi in self.get_pi_creatures()
|
||||
]
|
||||
)
|
||||
self.play(
|
||||
|
|
@ -2741,7 +2741,7 @@ class NextVideo(TeacherStudentsScene):
|
|||
Write(mob, run_time = 1),
|
||||
*[
|
||||
ApplyMethod(pi.look_at, mob)
|
||||
for pi in self.get_everyone()
|
||||
for pi in self.get_pi_creatures()
|
||||
]
|
||||
)
|
||||
self.dither(3)
|
||||
|
|
|
|||
99
eoc/chapter4.py
Normal file
99
eoc/chapter4.py
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
from helpers import *
|
||||
|
||||
from mobject.tex_mobject import TexMobject
|
||||
from mobject import Mobject
|
||||
from mobject.image_mobject import ImageMobject
|
||||
from mobject.vectorized_mobject import *
|
||||
|
||||
from animation.animation import Animation
|
||||
from animation.transform import *
|
||||
from animation.simple_animations import *
|
||||
from animation.playground import *
|
||||
from topics.geometry import *
|
||||
from topics.characters import *
|
||||
from topics.functions import *
|
||||
from topics.fractals import *
|
||||
from topics.number_line import *
|
||||
from topics.combinatorics import *
|
||||
from topics.numerals import *
|
||||
from topics.three_dimensions import *
|
||||
from topics.objects import *
|
||||
from scene import Scene
|
||||
from scene.zoomed_scene import ZoomedScene
|
||||
from camera import Camera
|
||||
from mobject.svg_mobject import *
|
||||
from mobject.tex_mobject import *
|
||||
|
||||
from eoc.chapter1 import OpeningQuote, PatreonThanks
|
||||
from eoc.graph_scene import *
|
||||
|
||||
|
||||
class Chapter3OpeningQuote(OpeningQuote):
|
||||
CONFIG = {
|
||||
"quote" : [
|
||||
"Using the chain rule is like peeling an onion: ",
|
||||
"you have to deal with each layer at a time, and ",
|
||||
"if it is too big you will start crying."
|
||||
],
|
||||
"author" : "(Anonymous professor)"
|
||||
}
|
||||
|
||||
class TransitionFromLastVideo(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
rules = power_rule, sine_rule, exp_rule = VGroup(*[
|
||||
TexMobject("\\frac{d(x^3)}{dx} = 3x^2"),
|
||||
TexMobject("\\frac{d(\\sin(x))}{dx} = \\cos(x)"),
|
||||
TexMobject("\\frac{d(e^x)}{dx} = e^x"),
|
||||
])
|
||||
rules.arrange_submobjects(buff = LARGE_BUFF)
|
||||
rules.next_to(self.get_teacher(), UP, buff = MED_LARGE_BUFF)
|
||||
rules.to_edge(LEFT)
|
||||
|
||||
self.add(rules)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1018,14 +1018,14 @@ class MentionGenerality(TeacherStudentsScene, ThreeDScene):
|
|||
Write(arrow),
|
||||
*[
|
||||
ApplyMethod(pi.look_at, arrow)
|
||||
for pi in self.get_everyone()
|
||||
for pi in self.get_pi_creatures()
|
||||
]
|
||||
)
|
||||
self.change_student_modes("pondering", "erm", "confused")
|
||||
self.dither()
|
||||
self.play(*[
|
||||
ApplyMethod(pi.look_at, arrow)
|
||||
for pi in self.get_everyone()
|
||||
for pi in self.get_pi_creatures()
|
||||
])
|
||||
self.play(Write(formula))
|
||||
self.dither(3)
|
||||
|
|
@ -2297,7 +2297,7 @@ class ExclaimBorsukUlam(TeacherStudentsScene):
|
|||
)
|
||||
self.play(*[
|
||||
ApplyMethod(pi.change_mode, "hooray")
|
||||
for pi in self.get_everyone()
|
||||
for pi in self.get_pi_creatures()
|
||||
])
|
||||
self.dither(3)
|
||||
|
||||
|
|
|
|||
|
|
@ -794,7 +794,7 @@ class ProfessorsTry(Scene):
|
|||
morty = Mortimer()
|
||||
morty.to_corner(DOWN+RIGHT)
|
||||
morty.shift(3*LEFT)
|
||||
speech_bubble = morty.get_bubble("speech", height = 4, width = 8)
|
||||
speech_bubble = morty.get_bubble(SpeechBubble, height = 4, width = 8)
|
||||
speech_bubble.shift(RIGHT)
|
||||
words = TextMobject(
|
||||
"It really is beautiful! I want you to \\\\" + \
|
||||
|
|
@ -922,7 +922,7 @@ class ResourceForTeachers(Scene):
|
|||
def construct(self):
|
||||
morty = Mortimer(mode = "speaking")
|
||||
morty.to_corner(DOWN + RIGHT)
|
||||
bubble = morty.get_bubble("speech")
|
||||
bubble = morty.get_bubble(SpeechBubble)
|
||||
bubble.write("I'm assuming you \\\\ know linear algebra\\dots")
|
||||
words = bubble.content
|
||||
bubble.clear()
|
||||
|
|
|
|||
|
|
@ -430,7 +430,7 @@ class HelpsToHaveOneThought(Scene):
|
|||
randys.to_corner(DOWN+LEFT)
|
||||
randy = randys.split()[1]
|
||||
|
||||
speech_bubble = morty.get_bubble("speech")
|
||||
speech_bubble = morty.get_bubble(SpeechBubble)
|
||||
words = TextMobject("Think of some vector...")
|
||||
speech_bubble.position_mobject_inside(words)
|
||||
thought_bubble = randy.get_bubble()
|
||||
|
|
@ -1119,8 +1119,8 @@ class ItDoesntMatterWhich(Scene):
|
|||
for pi in physy, compy:
|
||||
pi.next_to(pi.title, UP)
|
||||
self.add(pi, pi.title)
|
||||
compy_speech = compy.get_bubble("speech")
|
||||
physy_speech = physy.get_bubble("speech")
|
||||
compy_speech = compy.get_bubble(SpeechBubble)
|
||||
physy_speech = physy.get_bubble(SpeechBubble)
|
||||
arrow = Vector([2, 1])
|
||||
array = matrix_to_mobject([2, 1])
|
||||
goes_to = TexMobject("\\Rightarrow")
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ class StudentsFindThisConfusing(TeacherStudentsScene):
|
|||
Write(title),
|
||||
*[
|
||||
ApplyMethod(pi.look_at, title)
|
||||
for pi in self.get_everyone()
|
||||
for pi in self.get_pi_creatures()
|
||||
]
|
||||
)
|
||||
self.play(
|
||||
|
|
@ -608,7 +608,7 @@ class ContrastMatrixUnderstandingWithEigenvalue(TeacherStudentsScene):
|
|||
for mob in axis_and_rotation, matrix:
|
||||
mob.to_corner(UP+RIGHT)
|
||||
|
||||
everyone = self.get_everyone()
|
||||
everyone = self.get_pi_creatures()
|
||||
self.play(
|
||||
Write(axis_and_rotation),
|
||||
*it.chain(*zip(
|
||||
|
|
@ -752,7 +752,7 @@ class SymbolicEigenvectors(Scene):
|
|||
|
||||
morty = Mortimer().to_edge(DOWN)
|
||||
morty.change_mode("speaking")
|
||||
bubble = morty.get_bubble("speech", width = 5, direction = LEFT)
|
||||
bubble = morty.get_bubble(SpeechBubble, width = 5, direction = LEFT)
|
||||
VGroup(morty, bubble).to_edge(RIGHT)
|
||||
solve_text = TextMobject(
|
||||
"Solve for \\\\",
|
||||
|
|
@ -955,7 +955,7 @@ class SymbolicEigenvectors(Scene):
|
|||
randy = Randolph(mode = "speaking").to_edge(DOWN)
|
||||
randy.flip()
|
||||
randy.look_at(self.expression)
|
||||
bubble = randy.get_bubble("speech", direction = LEFT, width = 5)
|
||||
bubble = randy.get_bubble(SpeechBubble, direction = LEFT, width = 5)
|
||||
words = TextMobject("We need")
|
||||
equation = TexMobject(
|
||||
"\\det(A-", "\\lambda", "I)", "=0"
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ class WhatIsA2DVector(LinearTransformationScene):
|
|||
map(Animation, [cs_student.bubble, cs_student.arrow]),
|
||||
[mob.restore for mob in cs_student.v, cs_student.coords],
|
||||
))
|
||||
bubble = cs_student.get_bubble("speech", width = 4, height = 3)
|
||||
bubble = cs_student.get_bubble(SpeechBubble, width = 4, height = 3)
|
||||
bubble.set_fill(BLACK, opacity = 1)
|
||||
bubble.next_to(cs_student, UP+LEFT)
|
||||
bubble.write("Consider higher \\\\ dimensions")
|
||||
|
|
@ -293,7 +293,7 @@ class AskAbout4DPhysicsStudent(Scene):
|
|||
compy = CSStudent().to_edge(DOWN).shift(2*RIGHT)
|
||||
for pi1, pi2 in (physy, compy), (compy, physy):
|
||||
pi1.look_at(pi2.eyes)
|
||||
physy.bubble = physy.get_bubble("speech", width = 5, height = 4.5)
|
||||
physy.bubble = physy.get_bubble(SpeechBubble, width = 5, height = 4.5)
|
||||
|
||||
line = Line(LEFT, RIGHT, color = BLUE_B)
|
||||
square = Square(color = BLUE_C)
|
||||
|
|
@ -541,7 +541,7 @@ class WhatIsSpace(Scene):
|
|||
physy.bubble = get_small_bubble(physy)
|
||||
vector = Vector([1, 2])
|
||||
physy.bubble.add_content(vector)
|
||||
compy.bubble = compy.get_bubble("speech", width = 6, height = 4)
|
||||
compy.bubble = compy.get_bubble(SpeechBubble, width = 6, height = 4)
|
||||
compy.bubble.set_fill(BLACK, opacity = 1)
|
||||
compy.bubble.write("What exactly do\\\\ you mean by ``space''?")
|
||||
|
||||
|
|
@ -1017,7 +1017,7 @@ class TransformationsAndOperators(TeacherStudentsScene):
|
|||
""", student_index = 0)
|
||||
self.random_blink()
|
||||
teacher = self.get_teacher()
|
||||
bubble = teacher.get_bubble("speech", height = 2, width = 2)
|
||||
bubble = teacher.get_bubble(SpeechBubble, height = 2, width = 2)
|
||||
bubble.set_fill(BLACK, opacity = 1)
|
||||
bubble.write("Yup!")
|
||||
self.play(
|
||||
|
|
@ -1280,7 +1280,7 @@ class FormalDefinitionOfLinear(LinearTransformationScene):
|
|||
|
||||
def add_words(self):
|
||||
randy = Randolph().shift(LEFT).to_edge(DOWN)
|
||||
bubble = randy.get_bubble("speech", width = 6, height = 4)
|
||||
bubble = randy.get_bubble(SpeechBubble, width = 6, height = 4)
|
||||
bubble.set_fill(BLACK, opacity = 0.8)
|
||||
bubble.shift(0.5*DOWN)
|
||||
VGroup(randy, bubble).to_edge(RIGHT, buff = 0)
|
||||
|
|
@ -1901,7 +1901,7 @@ class MatrixVectorMultiplicationAndDerivative(TeacherStudentsScene):
|
|||
arrow.highlight(BLACK)
|
||||
|
||||
teacher = self.get_teacher()
|
||||
bubble = teacher.get_bubble("speech", height = 4)
|
||||
bubble = teacher.get_bubble(SpeechBubble, height = 4)
|
||||
bubble.add_content(group)
|
||||
|
||||
self.play(
|
||||
|
|
@ -2146,7 +2146,7 @@ class MathematicianSpeakingToAll(Scene):
|
|||
others.scale(0.8)
|
||||
others.to_corner(DOWN+RIGHT)
|
||||
|
||||
bubble = mathy.get_bubble("speech")
|
||||
bubble = mathy.get_bubble(SpeechBubble)
|
||||
bubble.write("""
|
||||
I don't want to think
|
||||
about all y'all's crazy
|
||||
|
|
@ -2162,7 +2162,7 @@ class MathematicianSpeakingToAll(Scene):
|
|||
)
|
||||
self.play(Blink(others[3]))
|
||||
self.dither()
|
||||
thought_bubble = mathy.get_bubble("thought")
|
||||
thought_bubble = mathy.get_bubble(ThoughtBubble)
|
||||
self.play(
|
||||
FadeOut(bubble.content),
|
||||
Transform(bubble, thought_bubble),
|
||||
|
|
@ -2408,7 +2408,7 @@ class VectorSpaceOfPiCreatures(Scene):
|
|||
class MathematicianDoesntHaveToThinkAboutThat(Scene):
|
||||
def construct(self):
|
||||
mathy = Mathematician().to_corner(DOWN+LEFT)
|
||||
bubble = mathy.get_bubble("thought", height = 4)
|
||||
bubble = mathy.get_bubble(ThoughtBubble, height = 4)
|
||||
words = TextMobject("I don't have to worry", "\\\\ about that madness!")
|
||||
bubble.add_content(words)
|
||||
new_words = TextMobject("So long as I", "\\\\ work abstractly")
|
||||
|
|
|
|||
|
|
@ -651,7 +651,7 @@ class SpeakingDifferentLanguages(JenniferScene):
|
|||
jenny.coords = Matrix(["5/3", "1/3"])
|
||||
jenny.text = TextMobject("Non, c'est")
|
||||
for pi in jenny, you:
|
||||
pi.bubble = pi.get_bubble("speech", width = 4.5, height = 3.5)
|
||||
pi.bubble = pi.get_bubble(SpeechBubble, width = 4.5, height = 3.5)
|
||||
if pi is you:
|
||||
pi.bubble.shift(MED_SMALL_BUFF*RIGHT)
|
||||
else:
|
||||
|
|
@ -720,7 +720,7 @@ class JennysGrid(JenniferScene):
|
|||
def construct(self):
|
||||
self.add(self.jenny)
|
||||
self.jenny.shift(3*RIGHT)
|
||||
bubble = self.jenny.get_bubble("speech", width = 4)
|
||||
bubble = self.jenny.get_bubble(SpeechBubble, width = 4)
|
||||
bubble.flip()
|
||||
bubble.set_fill(BLACK, opacity = 0.8)
|
||||
bubble.to_edge(LEFT)
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ class Chapter9(Scene):
|
|||
you.coords = Matrix([3, 2])
|
||||
jenny.coords = Matrix(["5/3", "1/3"])
|
||||
for pi in jenny, you:
|
||||
pi.bubble = pi.get_bubble("speech", width = 3, height = 3)
|
||||
pi.bubble = pi.get_bubble(SpeechBubble, width = 3, height = 3)
|
||||
if pi is you:
|
||||
pi.bubble.shift(MED_SMALL_BUFF*RIGHT)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ class WhatAreFractals(TeacherStudentsScene):
|
|||
FadeIn(picture),
|
||||
*[
|
||||
ApplyMethod(pi.look_at, name)
|
||||
for pi in self.get_everyone()
|
||||
for pi in self.get_pi_creatures()
|
||||
]
|
||||
)
|
||||
self.dither(2)
|
||||
|
|
@ -2337,7 +2337,7 @@ class DefineFractal(TeacherStudentsScene):
|
|||
self.change_student_modes(*["pondering"]*3)
|
||||
self.play(*[
|
||||
ApplyMethod(pi.look, DOWN)
|
||||
for pi in self.get_everyone()
|
||||
for pi in self.get_pi_creatures()
|
||||
])
|
||||
self.dither(3)
|
||||
|
||||
|
|
|
|||
|
|
@ -541,7 +541,7 @@ class IntroduceKeith(Scene):
|
|||
randy = Randolph().next_to(keith, LEFT, LARGE_BUFF, aligned_edge = DOWN)
|
||||
randy.shift_onto_screen()
|
||||
|
||||
bubble = keith.get_bubble("speech", width = 7)
|
||||
bubble = keith.get_bubble(SpeechBubble, width = 7)
|
||||
bubble.write("01101011 $\\Rightarrow$ Towers of Hanoi")
|
||||
zero_width = bubble.content[0].get_width()
|
||||
one_width = bubble.content[1].get_width()
|
||||
|
|
@ -555,7 +555,7 @@ class IntroduceKeith(Scene):
|
|||
bubble.pin_to(keith)
|
||||
VGroup(bubble, bubble.content).shift(DOWN)
|
||||
|
||||
randy.bubble = randy.get_bubble("speech", height = 3)
|
||||
randy.bubble = randy.get_bubble(SpeechBubble, height = 3)
|
||||
randy.bubble.write("Wait, what's \\\\ Towers of Hanoi?")
|
||||
|
||||
title = TextMobject("Keith Schwarz (Computer scientist)")
|
||||
|
|
@ -803,7 +803,7 @@ class KeithShowingBinary(Scene):
|
|||
keith.next_to(morty, LEFT, buff = 2*LARGE_BUFF)
|
||||
randy = Randolph()
|
||||
randy.next_to(keith, LEFT, buff = 2*LARGE_BUFF)
|
||||
randy.bubble = randy.get_bubble("speech")
|
||||
randy.bubble = randy.get_bubble(SpeechBubble)
|
||||
randy.bubble.set_fill(BLACK, opacity = 1)
|
||||
randy.bubble.write("Hold on...how does \\\\ binary work again?")
|
||||
|
||||
|
|
@ -1053,7 +1053,7 @@ class IntroduceBinaryCounting(BinaryCountingScene):
|
|||
|
||||
def initial_counting(self):
|
||||
randy = Randolph().to_corner(DOWN+LEFT)
|
||||
bubble = randy.get_bubble("thought", height = 3.4, width = 5)
|
||||
bubble = randy.get_bubble(ThoughtBubble, height = 3.4, width = 5)
|
||||
bubble.write(
|
||||
"Not ten, not ten \\\\",
|
||||
"\\quad not ten, not ten..."
|
||||
|
|
@ -1436,7 +1436,7 @@ class RecursionTime(Scene):
|
|||
|
||||
self.add(keith, morty)
|
||||
|
||||
bubble = keith.get_bubble("speech", height = 2)
|
||||
bubble = keith.get_bubble(SpeechBubble, height = 2)
|
||||
bubble.write("Recursion time!!!")
|
||||
VGroup(bubble, bubble.content).shift(UP)
|
||||
|
||||
|
|
@ -1704,7 +1704,7 @@ class KeithSaysBigToSmall(Scene):
|
|||
def construct(self):
|
||||
keith = Keith()
|
||||
keith.shift(2.5*DOWN + 3*LEFT)
|
||||
bubble = keith.get_bubble("speech", height = 4.5)
|
||||
bubble = keith.get_bubble(SpeechBubble, height = 4.5)
|
||||
bubble.write("""
|
||||
Big problem
|
||||
$\\Downarrow$
|
||||
|
|
@ -1730,7 +1730,7 @@ class CodeThisUp(Scene):
|
|||
morty.shift(2*DOWN+3*RIGHT)
|
||||
keith.make_eye_contact(morty)
|
||||
point = 2*UP+3*RIGHT
|
||||
bubble = keith.get_bubble("speech", width = 4.5, height = 3)
|
||||
bubble = keith.get_bubble(SpeechBubble, width = 4.5, height = 3)
|
||||
bubble.write("This is the \\\\ most efficient")
|
||||
self.add(morty, keith)
|
||||
|
||||
|
|
@ -1772,7 +1772,7 @@ class NoRoomForInefficiency(Scene):
|
|||
def construct(self):
|
||||
morty = Mortimer().flip()
|
||||
morty.shift(2.5*DOWN+3*LEFT)
|
||||
bubble = morty.get_bubble("speech", width = 4)
|
||||
bubble = morty.get_bubble(SpeechBubble, width = 4)
|
||||
bubble.write("No room for \\\\ inefficiency")
|
||||
VGroup(morty, bubble, bubble.content).to_corner(DOWN+RIGHT)
|
||||
|
||||
|
|
@ -1792,7 +1792,7 @@ class WhyDoesBinaryAchieveThis(Scene):
|
|||
morty = Mortimer()
|
||||
morty.shift(2*DOWN+3*RIGHT)
|
||||
keith.make_eye_contact(morty)
|
||||
bubble = morty.get_bubble("speech", width = 5, height = 3)
|
||||
bubble = morty.get_bubble(SpeechBubble, width = 5, height = 3)
|
||||
bubble.write("""
|
||||
Why does counting
|
||||
in binary work?
|
||||
|
|
@ -1814,7 +1814,7 @@ class BothAreSelfSimilar(Scene):
|
|||
def construct(self):
|
||||
morty = Mortimer().flip()
|
||||
morty.shift(2.5*DOWN+3*LEFT)
|
||||
bubble = morty.get_bubble("speech")
|
||||
bubble = morty.get_bubble(SpeechBubble)
|
||||
bubble.write("Both are self-similar")
|
||||
|
||||
self.add(morty)
|
||||
|
|
@ -2071,7 +2071,7 @@ class StillRecruse(Scene):
|
|||
morty.shift(2*DOWN+3*RIGHT)
|
||||
keith.make_eye_contact(morty)
|
||||
point = 2*UP+3*RIGHT
|
||||
bubble = keith.get_bubble("speech", width = 4.5, height = 3)
|
||||
bubble = keith.get_bubble(SpeechBubble, width = 4.5, height = 3)
|
||||
bubble.write("You can still\\\\ use recursion")
|
||||
self.add(morty, keith)
|
||||
|
||||
|
|
@ -2693,7 +2693,7 @@ class KeithAsksAboutConfigurations(Scene):
|
|||
keith = Keith().shift(2*DOWN+3*LEFT)
|
||||
morty = Mortimer().shift(2*DOWN+3*RIGHT)
|
||||
keith.make_eye_contact(morty)
|
||||
bubble = keith.get_bubble("speech")
|
||||
bubble = keith.get_bubble(SpeechBubble)
|
||||
bubble.write("Think about how many \\\\ configurations there are.")
|
||||
|
||||
self.add(keith, morty)
|
||||
|
|
@ -3237,7 +3237,7 @@ class MentionFinalAnimation(Scene):
|
|||
def construct(self):
|
||||
morty = Mortimer()
|
||||
morty.shift(2*DOWN+3*RIGHT)
|
||||
bubble = morty.get_bubble("speech", width = 6)
|
||||
bubble = morty.get_bubble(SpeechBubble, width = 6)
|
||||
bubble.write("Before the final\\\\ animation...")
|
||||
|
||||
self.add(morty)
|
||||
|
|
|
|||
|
|
@ -529,7 +529,7 @@ class KindWordsOnEoLA(TeacherStudentsScene):
|
|||
ShowCreation(rect),
|
||||
*[
|
||||
ApplyMethod(pi.look_at, rect)
|
||||
for pi in self.get_everyone()
|
||||
for pi in self.get_pi_creatures()
|
||||
],
|
||||
run_time = 2
|
||||
)
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ class ReactionsToTattoo(PiCreatureScene):
|
|||
self.dither(2)
|
||||
|
||||
|
||||
def get_pi_creature(self):
|
||||
def create_pi_creature(self):
|
||||
randy = Randolph()
|
||||
randy.next_to(ORIGIN, DOWN)
|
||||
return randy
|
||||
|
|
|
|||
|
|
@ -413,11 +413,11 @@ class WhenIWasAKid(TeacherStudentsScene):
|
|||
speaker.to_edge(RIGHT)
|
||||
return speaker
|
||||
|
||||
def get_everyone(self):
|
||||
def get_pi_creatures(self):
|
||||
if hasattr(self, "everyone"):
|
||||
return self.everyone
|
||||
else:
|
||||
return TeacherStudentsScene.get_everyone(self)
|
||||
return TeacherStudentsScene.get_pi_creatures(self)
|
||||
|
||||
class FormingTheMobiusStrip(Scene):
|
||||
def construct(self):
|
||||
|
|
@ -1438,7 +1438,7 @@ class NotHelpful(Scene):
|
|||
def construct(self):
|
||||
morty = Mortimer()
|
||||
morty.next_to(ORIGIN, DOWN)
|
||||
bubble = morty.get_bubble("speech", width = 4, height = 3)
|
||||
bubble = morty.get_bubble(SpeechBubble, width = 4, height = 3)
|
||||
bubble.write("Not helpful!")
|
||||
|
||||
self.add(morty)
|
||||
|
|
|
|||
|
|
@ -403,7 +403,7 @@ class WhyPeopleMayKnowIt(TeacherStudentsScene):
|
|||
#Thoughts
|
||||
self.play(*it.chain(*[
|
||||
[pi.change_mode, "pondering", pi.look_at, func_mob]
|
||||
for pi in self.get_everyone()
|
||||
for pi in self.get_pi_creatures()
|
||||
]))
|
||||
self.random_blink()
|
||||
self.student_thinks(
|
||||
|
|
@ -425,7 +425,7 @@ class WhyPeopleMayKnowIt(TeacherStudentsScene):
|
|||
self.random_blink()
|
||||
self.play(*it.chain(*[
|
||||
[pi.change_mode, "confused", pi.look_at, divergent_sum]
|
||||
for pi in self.get_everyone()
|
||||
for pi in self.get_pi_creatures()
|
||||
]))
|
||||
self.dither()
|
||||
self.random_blink()
|
||||
|
|
@ -934,7 +934,7 @@ class IgnoreNegatives(TeacherStudentsScene):
|
|||
Write(only_s_gt_1),
|
||||
*it.chain(*[
|
||||
[pi.look_at, definition]
|
||||
for pi in self.get_everyone()
|
||||
for pi in self.get_pi_creatures()
|
||||
])
|
||||
)
|
||||
self.random_blink(3)
|
||||
|
|
@ -1270,7 +1270,7 @@ class FromRealToComplex(ComplexTransformationScene):
|
|||
morty = Mortimer().flip()
|
||||
morty.scale(0.7)
|
||||
morty.to_corner(DOWN+LEFT)
|
||||
bubble = morty.get_bubble("speech", height = 4)
|
||||
bubble = morty.get_bubble(SpeechBubble, height = 4)
|
||||
bubble.set_fill(BLACK, opacity = 0.5)
|
||||
bubble.write("""
|
||||
How can we visualize
|
||||
|
|
@ -1884,7 +1884,7 @@ class VisualizingSSquared(ComplexTransformationScene):
|
|||
morty = Mortimer().flip()
|
||||
morty.scale(0.7)
|
||||
morty.to_corner(DOWN+LEFT)
|
||||
bubble = morty.get_bubble("speech", height = 2, width = 4)
|
||||
bubble = morty.get_bubble(SpeechBubble, height = 2, width = 4)
|
||||
bubble.set_fill(BLACK, opacity = 0.9)
|
||||
bubble.write("""
|
||||
It all happens
|
||||
|
|
@ -1945,7 +1945,7 @@ class ShowZetaOnHalfPlane(ZetaTransformationScene):
|
|||
def react_to_transformation(self):
|
||||
morty = Mortimer().flip()
|
||||
morty.to_corner(DOWN+LEFT)
|
||||
bubble = morty.get_bubble("speech")
|
||||
bubble = morty.get_bubble(SpeechBubble)
|
||||
bubble.set_fill(BLACK, 0.5)
|
||||
bubble.write("\\emph{Damn}!")
|
||||
bubble.resize_to_content()
|
||||
|
|
@ -2332,7 +2332,7 @@ class IntroduceAnglePreservation(VisualizingSSquared):
|
|||
morty.to_corner(DOWN+RIGHT)
|
||||
randy.make_eye_contact(morty)
|
||||
for pi, words in (randy, "$f'(s) = 2s$"), (morty, "Here's some \\\\ related geometry..."):
|
||||
pi.bubble = pi.get_bubble("speech")
|
||||
pi.bubble = pi.get_bubble(SpeechBubble)
|
||||
pi.bubble.set_fill(BLACK, opacity = 0.7)
|
||||
pi.bubble.write(words)
|
||||
pi.bubble.resize_to_content()
|
||||
|
|
@ -3290,7 +3290,7 @@ class InventingMathPreview(Scene):
|
|||
class FinalAnimationTease(Scene):
|
||||
def construct(self):
|
||||
morty = Mortimer().shift(2*(DOWN+RIGHT))
|
||||
bubble = morty.get_bubble("speech")
|
||||
bubble = morty.get_bubble(SpeechBubble)
|
||||
bubble.write("""
|
||||
Want to know what
|
||||
$\\zeta'(s)$ looks like?
|
||||
|
|
|
|||
|
|
@ -82,19 +82,14 @@ class PiCreature(SVGMobject):
|
|||
return self
|
||||
|
||||
def change_mode(self, mode):
|
||||
curr_eye_center = self.eyes.get_center()
|
||||
curr_height = self.get_height()
|
||||
should_be_flipped = self.is_flipped()
|
||||
should_look = hasattr(self, "purposeful_looking_direction")
|
||||
if should_look:
|
||||
looking_direction = self.purposeful_looking_direction
|
||||
self.__init__(mode)
|
||||
self.scale_to_fit_height(curr_height)
|
||||
self.shift(curr_eye_center - self.eyes.get_center())
|
||||
if should_be_flipped ^ self.is_flipped():
|
||||
self.flip()
|
||||
if should_look:
|
||||
self.look(looking_direction)
|
||||
new_self = self.__class__(mode = mode)
|
||||
new_self.scale_to_fit_height(self.get_height())
|
||||
new_self.shift(self.eyes.get_center() - new_self.eyes.get_center())
|
||||
if self.is_flipped() ^ new_self.is_flipped():
|
||||
new_self.flip()
|
||||
if hasattr(self, "purposeful_looking_direction"):
|
||||
new_self.look(self.purposeful_looking_direction)
|
||||
Transform(self, new_self).update(1)
|
||||
return self
|
||||
|
||||
def look(self, direction):
|
||||
|
|
@ -151,15 +146,14 @@ class PiCreature(SVGMobject):
|
|||
self.to_corner(DOWN+LEFT, **kwargs)
|
||||
return self
|
||||
|
||||
def get_bubble(self, bubble_type = "thought", **kwargs):
|
||||
#TODO, change bubble_type arg to have type Bubble
|
||||
if bubble_type == "thought":
|
||||
bubble = ThoughtBubble(**kwargs)
|
||||
elif bubble_type == "speech":
|
||||
bubble = SpeechBubble(**kwargs)
|
||||
else:
|
||||
raise Exception("%s is an invalid bubble type"%bubble_type)
|
||||
def get_bubble(self, bubble_class = ThoughtBubble, **kwargs):
|
||||
bubble = bubble_class(**kwargs)
|
||||
if "content" in kwargs:
|
||||
bubble.add_content(kwargs["content"])
|
||||
if "height" not in kwargs and "width" not in kwargs:
|
||||
bubble.resize_to_content()
|
||||
bubble.pin_to(self)
|
||||
self.bubble = bubble
|
||||
return bubble
|
||||
|
||||
def make_eye_contact(self, pi_creature):
|
||||
|
|
@ -233,9 +227,10 @@ class Blink(ApplyMethod):
|
|||
ApplyMethod.__init__(self, pi_creature.blink, **kwargs)
|
||||
|
||||
|
||||
class PiCreatureSays(AnimationGroup):
|
||||
class PiCreatureBubbleIntroduction(AnimationGroup):
|
||||
CONFIG = {
|
||||
"target_mode" : "speaking",
|
||||
"bubble_class" : SpeechBubble,
|
||||
"change_mode_kwargs" : {},
|
||||
"bubble_creation_kwargs" : {},
|
||||
"bubble_kwargs" : {},
|
||||
|
|
@ -244,12 +239,15 @@ class PiCreatureSays(AnimationGroup):
|
|||
}
|
||||
def __init__(self, pi_creature, *content, **kwargs):
|
||||
digest_config(self, kwargs)
|
||||
bubble = pi_creature.get_bubble("speech", **self.bubble_kwargs)
|
||||
bubble.write(*content)
|
||||
if "height" not in self.bubble_kwargs and "width" not in self.bubble_kwargs:
|
||||
bubble.resize_to_content()
|
||||
bubble.pin_to(pi_creature)
|
||||
pi_creature.bubble = bubble
|
||||
if isinstance(content, Mobject):
|
||||
bubble_content = content
|
||||
else:
|
||||
bubble_content = TextMobject(*content)
|
||||
bubble = pi_creature.get_bubble(
|
||||
self.bubble_class,
|
||||
content = bubble_content,
|
||||
**self.bubble_kwargs
|
||||
)
|
||||
|
||||
pi_creature.generate_target()
|
||||
pi_creature.target.change_mode(self.target_mode)
|
||||
|
|
@ -263,102 +261,203 @@ class PiCreatureSays(AnimationGroup):
|
|||
Write(bubble.content, **self.write_kwargs),
|
||||
**kwargs
|
||||
)
|
||||
|
||||
class PiCreatureSays(PiCreatureBubbleIntroduction):
|
||||
CONFIG = {
|
||||
"target_mode" : "speaking",
|
||||
"bubble_class" : SpeechBubble,
|
||||
}
|
||||
|
||||
class RemovePiCreatureBubble(AnimationGroup):
|
||||
CONFIG = {
|
||||
"target_mode" : "plain"
|
||||
}
|
||||
def __init__(self, pi_creature, **kwargs):
|
||||
assert hasattr(pi_creature, "bubble")
|
||||
digest_config(self, kwargs, locals())
|
||||
|
||||
AnimationGroup.__init__(
|
||||
self,
|
||||
ApplyMethod(pi_creature.change_mode, self.target_mode),
|
||||
FadeOut(pi_creature.bubble),
|
||||
FadeOut(pi_creature.bubble.content),
|
||||
)
|
||||
|
||||
def clean_up(self):
|
||||
AnimationGroup.clean_up(self)
|
||||
self.pi_creature.bubble = None
|
||||
|
||||
|
||||
class PiCreatureScene(Scene):
|
||||
CONFIG = {
|
||||
"total_dither_time" : 0,
|
||||
"use_morty" : True,
|
||||
"seconds_to_blink" : 3,
|
||||
}
|
||||
def setup(self):
|
||||
self.pi_creature = self.get_pi_creature()
|
||||
self.add(self.pi_creature)
|
||||
self.pi_creatures = VGroup(*self.create_pi_creatures())
|
||||
self.add(self.pi_creatures)
|
||||
|
||||
def get_pi_creature(self):
|
||||
if self.use_morty:
|
||||
return Mortimer().to_corner(DOWN+RIGHT)
|
||||
else:
|
||||
return Randolph().to_corner(DOWN+LEFT)
|
||||
def create_pi_creatures(self):
|
||||
"""
|
||||
Likely updated for subclasses
|
||||
"""
|
||||
return VGroup(self.create_pi_creature())
|
||||
|
||||
def say(self, *content, **kwargs):
|
||||
added_anims = kwargs.get("added_anims", [])
|
||||
if "target_mode" in kwargs:
|
||||
target_mode = kwargs["target_mode"]
|
||||
else:
|
||||
target_mode = "speaking"
|
||||
added_anims += [self.pi_creature.change_mode, target_mode]
|
||||
def create_pi_creature(self):
|
||||
return Mortimer().to_corner(DOWN+RIGHT)
|
||||
|
||||
def get_pi_creatures(self):
|
||||
return self.pi_creatures
|
||||
|
||||
def get_primary_pi_creature(self):
|
||||
return self.pi_creatures[0]
|
||||
|
||||
def introduce_bubble(
|
||||
self,
|
||||
pi_creature,
|
||||
bubble_class,
|
||||
content = None,
|
||||
target_mode = None,
|
||||
bubble_kwargs = None,
|
||||
bubble_removal_kwargs = None,
|
||||
added_anims = None,
|
||||
**kwargs
|
||||
):
|
||||
content = content or []
|
||||
if target_mode is None:
|
||||
target_mode = "thinking" if bubble_class is ThoughtBubble else "speaking"
|
||||
bubble_kwargs = bubble_kwargs or dict()
|
||||
bubble_removal_kwargs = bubble_removal_kwargs or dict()
|
||||
added_anims = added_anims or []
|
||||
|
||||
pi_creatures_with_bubbles = [
|
||||
pi for pi in self.get_pi_creatures()
|
||||
if pi is not pi_creature
|
||||
if hasattr(pi, "bubble") and pi.bubble is not None
|
||||
]
|
||||
added_anims += [
|
||||
RemovePiCreatureBubble(pi, **bubble_removal_kwargs)
|
||||
for pi in pi_creatures_with_bubbles
|
||||
]
|
||||
self.play(
|
||||
PiCreatureSays(self.pi_creature, *content, **kwargs),
|
||||
*added_anims
|
||||
PiCreatureBubbleIntroduction(
|
||||
pi_creature,
|
||||
*content,
|
||||
bubble_class = bubble_class,
|
||||
bubble_kwargs = bubble_kwargs,
|
||||
target_mode = target_mode
|
||||
),
|
||||
*added_anims,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
def get_bubble_fade_anims(self, target_mode = "plain"):
|
||||
def pi_creature_says(self, pi_creature, *content, **kwargs):
|
||||
self.introduce_bubble(
|
||||
pi_creature,
|
||||
bubble_class = SpeechBubble,
|
||||
content = content,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
def pi_creature_thinks(self, pi_creature, *content, **kwargs):
|
||||
self.introduce_bubble(
|
||||
pi_creature,
|
||||
bubble_class = ThoughtBubble,
|
||||
content = content,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
def say(self, *content, **kwargs):
|
||||
self.pi_creature_says(self.get_primary_pi_creature(), *content, **kwargs)
|
||||
|
||||
def think(self, *content, **kwargs):
|
||||
self.pi_creature_thinks(self.get_primary_pi_creature(), *content, **kwargs)
|
||||
|
||||
def get_bubble_fade_anims(self, **kwargs):
|
||||
return [
|
||||
FadeOut(self.pi_creature.bubble),
|
||||
FadeOut(self.pi_creature.bubble.content),
|
||||
self.pi_creature.change_mode, target_mode
|
||||
RemovePiCreatureBubble(pi_creature, **kwargs)
|
||||
for pi_creature in self.get_pi_creatures()
|
||||
if hasattr(pi_creature.bubble)
|
||||
]
|
||||
|
||||
def compile_play_args_to_animation_list(self, *args):
|
||||
"""
|
||||
Add animations so that all pi creatures look at the
|
||||
first mobject being animated with each .play call
|
||||
"""
|
||||
animations = Scene.compile_play_args_to_animation_list(self, *args)
|
||||
if self.pi_creature not in self.get_mobjects():
|
||||
return animations
|
||||
if len(animations) == 0:
|
||||
return animations
|
||||
first_anim = animations[0]
|
||||
if first_anim.mobject is self.pi_creature:
|
||||
if isinstance(first_anim, Blink):
|
||||
return animations
|
||||
|
||||
#Look at ending state
|
||||
first_anim.update(1)
|
||||
point_of_interest = first_anim.mobject.get_center()
|
||||
first_anim.update(0)
|
||||
|
||||
last_anim = animations[-1]
|
||||
if last_anim.mobject is self.pi_creature and isinstance(last_anim, Transform):
|
||||
if isinstance(animations[-1], Transform):
|
||||
animations[-1].target_mobject.look_at(point_of_interest)
|
||||
return animations
|
||||
new_anim = ApplyMethod(self.pi_creature.look_at, point_of_interest)
|
||||
return list(animations) + [new_anim]
|
||||
for pi_creature in self.get_pi_creatures():
|
||||
if pi_creature not in self.get_mobjects():
|
||||
continue
|
||||
if pi_creature in first_anim.mobject.submobject_family():
|
||||
continue
|
||||
anims_with_pi_creature = [
|
||||
anim for anim in animations
|
||||
if pi_creature in anim.mobject.submobject_family()
|
||||
]
|
||||
if anims_with_pi_creature:
|
||||
for anim in animations:
|
||||
if isinstance(anim, Transform):
|
||||
index = anim.submobject_family().index(pi_creature)
|
||||
target_family = anim.target_mobject.submobject_family()
|
||||
target = target_family[index]
|
||||
if isinstance(target, PiCreature):
|
||||
target.look_at(point_of_interest)
|
||||
continue
|
||||
animations.append(
|
||||
ApplyMethod(pi_creature.look_at, point_of_interest)
|
||||
)
|
||||
return animations
|
||||
|
||||
def blink(self):
|
||||
self.play(Blink(self.pi_creature))
|
||||
self.play(Blink(random.choice(self.get_pi_creatures())))
|
||||
|
||||
def dither(self, time = 1, blink = True):
|
||||
while time > 0:
|
||||
if blink and self.total_dither_time%self.seconds_to_blink == 1:
|
||||
self.play(Blink(self.pi_creature))
|
||||
if blink and self.total_dither_time%self.seconds_to_blink == 0:
|
||||
self.blink()
|
||||
else:
|
||||
Scene.dither(self, time)
|
||||
Scene.dither(self)
|
||||
time -= 1
|
||||
self.total_dither_time += 1
|
||||
return self
|
||||
|
||||
def change_mode(self, mode):
|
||||
self.play(self.pi_creature.change_mode, mode)
|
||||
self.play(self.get_primary_pi_creature().change_mode, mode)
|
||||
|
||||
|
||||
class TeacherStudentsScene(Scene):
|
||||
def setup(self):
|
||||
class TeacherStudentsScene(PiCreatureScene):
|
||||
CONFIG = {
|
||||
"student_colors" : [BLUE_D, BLUE_C, BLUE_E],
|
||||
"student_scale_factor" : 0.8,
|
||||
"seconds_to_blink" : 2,
|
||||
}
|
||||
def create_pi_creatures(self):
|
||||
self.teacher = Mortimer()
|
||||
self.teacher.to_corner(DOWN + RIGHT)
|
||||
self.teacher.look(DOWN+LEFT)
|
||||
self.students = VGroup(*[
|
||||
Randolph(color = c)
|
||||
for c in BLUE_D, BLUE_C, BLUE_E
|
||||
for c in self.student_colors
|
||||
])
|
||||
self.students.arrange_submobjects(RIGHT)
|
||||
self.students.scale(0.8)
|
||||
self.students.scale(self.student_scale_factor)
|
||||
self.students.to_corner(DOWN+LEFT)
|
||||
self.teacher.look_at(self.students[-1].eyes)
|
||||
for student in self.students:
|
||||
student.look_at(self.teacher.eyes)
|
||||
|
||||
for pi_creature in self.get_everyone():
|
||||
pi_creature.bubble = None
|
||||
self.add(*self.get_everyone())
|
||||
return [self.teacher] + list(self.students)
|
||||
|
||||
def get_teacher(self):
|
||||
return self.teacher
|
||||
|
|
@ -366,74 +465,9 @@ class TeacherStudentsScene(Scene):
|
|||
def get_students(self):
|
||||
return self.students
|
||||
|
||||
def get_everyone(self):
|
||||
return [self.get_teacher()] + list(self.get_students())
|
||||
|
||||
def get_bubble_intro_animation(
|
||||
self, content, bubble_type, pi_creature,
|
||||
**bubble_kwargs
|
||||
):
|
||||
bubble = pi_creature.get_bubble(bubble_type, **bubble_kwargs)
|
||||
bubble.add_content(content)
|
||||
bubble.resize_to_content()
|
||||
if pi_creature.bubble:
|
||||
content_intro_anims = [
|
||||
Transform(pi_creature.bubble, bubble),
|
||||
Transform(pi_creature.bubble.content, bubble.content)
|
||||
]
|
||||
else:
|
||||
content_intro_anims = [
|
||||
FadeIn(bubble),
|
||||
Write(content),
|
||||
]
|
||||
pi_creature.bubble = bubble
|
||||
return content_intro_anims
|
||||
|
||||
def introduce_bubble(
|
||||
self, content, bubble_type, pi_creature,
|
||||
target_mode = None,
|
||||
added_anims = [],
|
||||
**bubble_kwargs
|
||||
):
|
||||
if all(map(lambda s : isinstance(s, str), content)):
|
||||
content = TextMobject(*content)
|
||||
elif len(content) == 1 and isinstance(content[0], Mobject):
|
||||
content = content[0]
|
||||
else:
|
||||
raise Exception("Invalid content type")
|
||||
|
||||
anims = []
|
||||
#Remove other bubbles
|
||||
for p in self.get_everyone():
|
||||
if (p.bubble is not None) and (p is not pi_creature):
|
||||
anims += [
|
||||
FadeOut(p.bubble),
|
||||
FadeOut(p.bubble.content)
|
||||
]
|
||||
p.bubble = None
|
||||
anims.append(ApplyMethod(p.change_mode, "plain"))
|
||||
#Bring in new bubble
|
||||
anims += self.get_bubble_intro_animation(
|
||||
content, bubble_type, pi_creature, **bubble_kwargs
|
||||
)
|
||||
#Add changing mode
|
||||
if not target_mode:
|
||||
if bubble_type is "speech":
|
||||
target_mode = "speaking"
|
||||
else:
|
||||
target_mode = "pondering"
|
||||
anims.append(
|
||||
ApplyMethod(
|
||||
pi_creature.change_mode,
|
||||
target_mode,
|
||||
)
|
||||
)
|
||||
self.play(*anims + added_anims)
|
||||
return pi_creature.bubble
|
||||
|
||||
def teacher_says(self, *content, **kwargs):
|
||||
return self.introduce_bubble(
|
||||
content, "speech", self.get_teacher(), **kwargs
|
||||
return self.pi_creature_says(
|
||||
self.get_teacher(), *content, **kwargs
|
||||
)
|
||||
|
||||
def student_says(self, *content, **kwargs):
|
||||
|
|
@ -444,25 +478,18 @@ class TeacherStudentsScene(Scene):
|
|||
])
|
||||
kwargs["target_mode"] = target_mode
|
||||
student = self.get_students()[kwargs.get("student_index", 1)]
|
||||
return self.introduce_bubble(content, "speech", student, **kwargs)
|
||||
return self.pi_creature_says(
|
||||
student, *content, **kwargs
|
||||
)
|
||||
|
||||
def teacher_thinks(self, *content, **kwargs):
|
||||
return self.introduce_bubble(
|
||||
content, "thought", self.get_teacher(), **kwargs
|
||||
return self.pi_creature_thinks(
|
||||
self.get_teacher(), *content, **kwargs
|
||||
)
|
||||
|
||||
def student_thinks(self, *content, **kwargs):
|
||||
student = self.get_students()[kwargs.get("student_index", 1)]
|
||||
return self.introduce_bubble(content, "thought", student, **kwargs)
|
||||
|
||||
def random_blink(self, num_times = 1):
|
||||
for x in range(num_times):
|
||||
pi_creature = random.choice(self.get_everyone())
|
||||
self.play(Blink(pi_creature))
|
||||
Scene.dither(self)
|
||||
|
||||
def dither(self, time = 1):
|
||||
self.random_blink(num_times = max(time/2, 1))
|
||||
return self.pi_creature_thinks(student, *content, **kwargs)
|
||||
|
||||
def change_student_modes(self, *modes, **kwargs):
|
||||
added_anims = kwargs.get("added_anims", [])
|
||||
|
|
@ -482,10 +509,9 @@ class TeacherStudentsScene(Scene):
|
|||
*added_anims
|
||||
)
|
||||
|
||||
|
||||
def zoom_in_on_thought_bubble(self, bubble = None, radius = SPACE_HEIGHT+SPACE_WIDTH):
|
||||
if bubble is None:
|
||||
for pi in self.get_everyone():
|
||||
for pi in self.get_pi_creatures():
|
||||
if hasattr(pi, "bubble") and isinstance(pi.bubble, ThoughtBubble):
|
||||
bubble = pi.bubble
|
||||
break
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue