mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
2^t example for exp_footnote in eoc
This commit is contained in:
parent
dc24f0eaf4
commit
01630a4958
3 changed files with 439 additions and 6 deletions
|
@ -25,7 +25,6 @@ from camera import Camera
|
||||||
from mobject.svg_mobject import *
|
from mobject.svg_mobject import *
|
||||||
from mobject.tex_mobject import *
|
from mobject.tex_mobject import *
|
||||||
|
|
||||||
from eoc.chapter1 import OpeningQuote, PatreonThanks
|
|
||||||
from eoc.graph_scene import *
|
from eoc.graph_scene import *
|
||||||
|
|
||||||
class LastVideo(TeacherStudentsScene):
|
class LastVideo(TeacherStudentsScene):
|
||||||
|
@ -48,7 +47,7 @@ class LastVideo(TeacherStudentsScene):
|
||||||
DOWN, buff = MED_LARGE_BUFF,
|
DOWN, buff = MED_LARGE_BUFF,
|
||||||
)
|
)
|
||||||
known_formulas.scale_to_fit_height(2.5)
|
known_formulas.scale_to_fit_height(2.5)
|
||||||
exp_question = TexMobject("2^x, 7^x, e^x ???")
|
exp_question = TexMobject("2^x", ", 7^x", ", e^x", " ???")
|
||||||
|
|
||||||
last_video_brace = Brace(last_video)
|
last_video_brace = Brace(last_video)
|
||||||
known_formulas.next_to(last_video_brace, DOWN)
|
known_formulas.next_to(last_video_brace, DOWN)
|
||||||
|
@ -96,8 +95,396 @@ class LastVideo(TeacherStudentsScene):
|
||||||
for pi in self.get_students()
|
for pi in self.get_students()
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
class PopulationSizeGraphVsPopulationMassGraph(Scene):
|
||||||
|
def construct(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class DoublingPopulation(PiCreatureScene):
|
||||||
|
CONFIG = {
|
||||||
|
"time_color" : YELLOW,
|
||||||
|
"pi_creature_grid_dimensions" : (8, 8),
|
||||||
|
"pi_creature_grid_height" : 6,
|
||||||
|
}
|
||||||
|
|
||||||
|
def construct(self):
|
||||||
|
self.remove(self.get_pi_creatures())
|
||||||
|
self.introduce_expression()
|
||||||
|
self.introduce_pi_creatures()
|
||||||
|
self.count_through_days()
|
||||||
|
self.ask_about_dM_dt()
|
||||||
|
self.growth_per_day()
|
||||||
|
self.relate_growth_rate_to_pop_size()
|
||||||
|
|
||||||
|
def introduce_expression(self):
|
||||||
|
f_x = TexMobject("f(x)", "=", "2^x")
|
||||||
|
f_t = TexMobject("f(t)", "=", "2^t")
|
||||||
|
P_t = TexMobject("P(t)", "=", "2^t")
|
||||||
|
M_t = TexMobject("M(t)", "=", "2^t")
|
||||||
|
functions = VGroup(f_x, f_t, P_t, M_t)
|
||||||
|
for function in functions:
|
||||||
|
function.scale(1.2)
|
||||||
|
function.to_corner(UP+LEFT)
|
||||||
|
for function in functions[1:]:
|
||||||
|
for i, j in (0, 2), (2, 1):
|
||||||
|
function[i][j].highlight(self.time_color)
|
||||||
|
|
||||||
|
t_expression = TexMobject("t", "=", "\\text{Time (in days)}")
|
||||||
|
t_expression.to_corner(UP+RIGHT)
|
||||||
|
t_expression[0].highlight(self.time_color)
|
||||||
|
|
||||||
|
pop_brace, mass_brace = [
|
||||||
|
Brace(function[0], DOWN)
|
||||||
|
for function in P_t, M_t
|
||||||
|
]
|
||||||
|
for brace, word in (pop_brace, "size"), (mass_brace, "mass"):
|
||||||
|
text = brace.get_text("Population %s"%word)
|
||||||
|
text.to_edge(LEFT)
|
||||||
|
brace.text = text
|
||||||
|
|
||||||
|
self.play(Write(f_x))
|
||||||
|
self.dither()
|
||||||
|
self.play(
|
||||||
|
Transform(f_x, f_t),
|
||||||
|
FadeIn(
|
||||||
|
t_expression,
|
||||||
|
run_time = 2,
|
||||||
|
submobject_mode = "lagged_start"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.play(Transform(f_x, P_t))
|
||||||
|
self.play(
|
||||||
|
GrowFromCenter(pop_brace),
|
||||||
|
Write(pop_brace.text, run_time = 2)
|
||||||
|
)
|
||||||
|
self.dither(2)
|
||||||
|
|
||||||
|
self.function = f_x
|
||||||
|
self.pop_brace = pop_brace
|
||||||
|
self.t_expression = t_expression
|
||||||
|
self.mass_function = M_t
|
||||||
|
self.mass_brace = mass_brace
|
||||||
|
|
||||||
|
def introduce_pi_creatures(self):
|
||||||
|
creatures = self.get_pi_creatures()
|
||||||
|
total_num_days = self.get_num_days()
|
||||||
|
num_start_days = 4
|
||||||
|
|
||||||
|
self.reset()
|
||||||
|
for x in range(num_start_days):
|
||||||
|
self.let_one_day_pass()
|
||||||
|
self.dither()
|
||||||
|
self.play(
|
||||||
|
Transform(self.function, self.mass_function),
|
||||||
|
Transform(self.pop_brace, self.mass_brace),
|
||||||
|
Transform(self.pop_brace.text, self.mass_brace.text),
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
for x in range(total_num_days-num_start_days):
|
||||||
|
self.let_one_day_pass()
|
||||||
|
self.dither()
|
||||||
|
self.joint_blink(shuffle = False)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
def count_through_days(self):
|
||||||
|
self.reset()
|
||||||
|
brace = self.get_population_size_descriptor()
|
||||||
|
days_to_let_pass = 3
|
||||||
|
|
||||||
|
self.play(GrowFromCenter(brace))
|
||||||
|
self.dither()
|
||||||
|
for x in range(days_to_let_pass):
|
||||||
|
self.let_one_day_pass()
|
||||||
|
new_brace = self.get_population_size_descriptor()
|
||||||
|
self.play(Transform(brace, new_brace))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
self.population_size_descriptor = brace
|
||||||
|
|
||||||
|
def ask_about_dM_dt(self):
|
||||||
|
dM_dt_question = TexMobject("{dM", "\\over dt}", "=", "???")
|
||||||
|
dM, dt, equals, q_marks = dM_dt_question
|
||||||
|
dM_dt_question.next_to(self.function, DOWN, buff = LARGE_BUFF)
|
||||||
|
dM_dt_question.to_edge(LEFT)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
FadeOut(self.pop_brace),
|
||||||
|
FadeOut(self.pop_brace.text),
|
||||||
|
Write(dM_dt_question)
|
||||||
|
)
|
||||||
|
self.dither(3)
|
||||||
|
for mob in dM, dt:
|
||||||
|
self.play(Indicate(mob))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
self.dM_dt_question = dM_dt_question
|
||||||
|
|
||||||
|
def growth_per_day(self):
|
||||||
|
day_to_day, frac = self.get_from_day_to_day_label()
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
FadeOut(self.dM_dt_question),
|
||||||
|
FadeIn(day_to_day)
|
||||||
|
)
|
||||||
|
rect = self.let_day_pass_and_highlight_new_creatures(frac)
|
||||||
|
|
||||||
|
for x in range(2):
|
||||||
|
new_day_to_day, new_frac = self.get_from_day_to_day_label()
|
||||||
|
self.play(*map(FadeOut, [rect, frac]))
|
||||||
|
frac = new_frac
|
||||||
|
self.play(Transform(day_to_day, new_day_to_day))
|
||||||
|
rect = self.let_day_pass_and_highlight_new_creatures(frac)
|
||||||
|
self.play(*map(FadeOut, [rect, frac, day_to_day]))
|
||||||
|
|
||||||
|
def let_day_pass_and_highlight_new_creatures(self, frac):
|
||||||
|
num_new_creatures = 2**self.get_curr_day()
|
||||||
|
brace = self.population_size_descriptor
|
||||||
|
|
||||||
|
self.let_one_day_pass()
|
||||||
|
new_brace = self.get_population_size_descriptor()
|
||||||
|
self.play(Transform(brace, new_brace))
|
||||||
|
new_creatures = VGroup(
|
||||||
|
*self.get_on_screen_pi_creatures()[-num_new_creatures:]
|
||||||
|
)
|
||||||
|
rect = Rectangle(
|
||||||
|
color = GREEN,
|
||||||
|
fill_color = BLUE,
|
||||||
|
fill_opacity = 0.3,
|
||||||
|
)
|
||||||
|
rect.replace(new_creatures, stretch = True)
|
||||||
|
rect.stretch_to_fit_height(rect.get_height()+MED_SMALL_BUFF)
|
||||||
|
rect.stretch_to_fit_width(rect.get_width()+MED_SMALL_BUFF)
|
||||||
|
self.play(DrawBorderThenFill(rect))
|
||||||
|
self.play(Write(frac))
|
||||||
|
self.dither()
|
||||||
|
return rect
|
||||||
|
|
||||||
|
def relate_growth_rate_to_pop_size(self):
|
||||||
|
false_deriv = TexMobject(
|
||||||
|
"{d(2^t) ", "\\over dt}", "= 2^t"
|
||||||
|
)
|
||||||
|
difference_eq = TexMobject(
|
||||||
|
"{ {2^{t+1} - 2^t} \\over", "1}", "= 2^t"
|
||||||
|
)
|
||||||
|
real_deriv = TexMobject(
|
||||||
|
"{ {2^{t+dt} - 2^t} \\over", "dt}", "= \\, ???"
|
||||||
|
)
|
||||||
|
VGroup(
|
||||||
|
false_deriv[0][3],
|
||||||
|
false_deriv[2][-1],
|
||||||
|
difference_eq[0][1],
|
||||||
|
difference_eq[0][-2],
|
||||||
|
difference_eq[2][-1],
|
||||||
|
difference_eq[2][-1],
|
||||||
|
real_deriv[0][1],
|
||||||
|
real_deriv[0][-2],
|
||||||
|
).highlight(YELLOW)
|
||||||
|
VGroup(
|
||||||
|
difference_eq[0][3],
|
||||||
|
difference_eq[1][-1],
|
||||||
|
real_deriv[0][3],
|
||||||
|
real_deriv[0][4],
|
||||||
|
real_deriv[1][-2],
|
||||||
|
real_deriv[1][-1],
|
||||||
|
).highlight(GREEN)
|
||||||
|
|
||||||
|
expressions = [false_deriv, difference_eq, real_deriv]
|
||||||
|
text_arg_list = [
|
||||||
|
("Tempting", "...",),
|
||||||
|
("Rate of change", "\\\\ per day"),
|
||||||
|
("Rate of change", "\\\\ in a small time"),
|
||||||
|
]
|
||||||
|
for expression, text_args in zip(expressions, text_arg_list):
|
||||||
|
expression.next_to(
|
||||||
|
self.function, DOWN,
|
||||||
|
buff = LARGE_BUFF,
|
||||||
|
aligned_edge = LEFT,
|
||||||
|
)
|
||||||
|
expression.brace = Brace(expression, DOWN)
|
||||||
|
expression.brace_text = expression.brace.get_text(*text_args)
|
||||||
|
|
||||||
|
time = self.t_expression[-1]
|
||||||
|
new_time = TexMobject("3")
|
||||||
|
new_time.move_to(time, LEFT)
|
||||||
|
|
||||||
|
fading_creatures = VGroup(*self.get_on_screen_pi_creatures()[8:])
|
||||||
|
|
||||||
|
brace = self.population_size_descriptor
|
||||||
|
|
||||||
|
self.play(*map(FadeIn, [
|
||||||
|
false_deriv, false_deriv.brace, false_deriv.brace_text
|
||||||
|
]))
|
||||||
|
self.dither()
|
||||||
|
self.play(
|
||||||
|
Transform(time, new_time),
|
||||||
|
FadeOut(fading_creatures)
|
||||||
|
)
|
||||||
|
new_brace = self.get_population_size_descriptor()
|
||||||
|
self.play(Transform(brace, new_brace))
|
||||||
|
self.dither()
|
||||||
|
for x in range(3):
|
||||||
|
self.let_one_day_pass(run_time = 2)
|
||||||
|
new_brace = self.get_population_size_descriptor()
|
||||||
|
self.play(Transform(brace, new_brace))
|
||||||
|
self.dither(2)
|
||||||
|
|
||||||
|
for expression in difference_eq, real_deriv:
|
||||||
|
expression.brace_text[1].highlight(GREEN)
|
||||||
|
self.play(
|
||||||
|
Transform(false_deriv, expression),
|
||||||
|
Transform(false_deriv.brace, expression.brace),
|
||||||
|
Transform(false_deriv.brace_text, expression.brace_text),
|
||||||
|
)
|
||||||
|
self.dither(3)
|
||||||
|
self.play(FadeOut(brace))
|
||||||
|
self.reset()
|
||||||
|
for x in range(self.get_num_days()):
|
||||||
|
self.let_one_day_pass()
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
rect = Rectangle(color = YELLOW)
|
||||||
|
rect.replace(real_deriv)
|
||||||
|
rect.stretch_to_fit_width(rect.get_width()+MED_SMALL_BUFF)
|
||||||
|
rect.stretch_to_fit_height(rect.get_height()+MED_SMALL_BUFF)
|
||||||
|
self.play(*map(FadeOut, [
|
||||||
|
false_deriv.brace, false_deriv.brace_text
|
||||||
|
]))
|
||||||
|
self.play(ShowCreation(rect))
|
||||||
|
self.play(*[
|
||||||
|
ApplyFunction(
|
||||||
|
lambda pi : pi.change_mode("pondering").look_at(real_deriv),
|
||||||
|
pi,
|
||||||
|
run_time = 2,
|
||||||
|
rate_func = squish_rate_func(smooth, a, a+0.5)
|
||||||
|
)
|
||||||
|
for pi in self.get_pi_creatures()
|
||||||
|
for a in [0.5*random.random()]
|
||||||
|
])
|
||||||
self.dither(3)
|
self.dither(3)
|
||||||
|
|
||||||
|
###########
|
||||||
|
|
||||||
|
def create_pi_creatures(self):
|
||||||
|
width, height = self.pi_creature_grid_dimensions
|
||||||
|
creature_array = VGroup(*[
|
||||||
|
VGroup(*[
|
||||||
|
PiCreature(mode = "plain")
|
||||||
|
for y in range(height)
|
||||||
|
]).arrange_submobjects(UP, buff = MED_LARGE_BUFF)
|
||||||
|
for x in range(width)
|
||||||
|
]).arrange_submobjects(RIGHT, buff = MED_LARGE_BUFF)
|
||||||
|
creatures = VGroup(*it.chain(*creature_array))
|
||||||
|
creatures.scale_to_fit_height(self.pi_creature_grid_height)
|
||||||
|
creatures.to_corner(DOWN+RIGHT)
|
||||||
|
|
||||||
|
colors = color_gradient([BLUE, GREEN, GREY_BROWN], len(creatures))
|
||||||
|
random.shuffle(colors)
|
||||||
|
for creature, color in zip(creatures, colors):
|
||||||
|
creature.set_color(color)
|
||||||
|
|
||||||
|
return creatures
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
time = self.t_expression[-1]
|
||||||
|
faders = [time] + list(self.get_on_screen_pi_creatures())
|
||||||
|
new_time = TexMobject("0")
|
||||||
|
new_time.next_to(self.t_expression[-2], RIGHT)
|
||||||
|
first_creature = self.get_pi_creatures()[0]
|
||||||
|
|
||||||
|
self.play(*map(FadeOut, faders))
|
||||||
|
self.play(*map(FadeIn, [first_creature, new_time]))
|
||||||
|
self.t_expression.submobjects[-1] = new_time
|
||||||
|
|
||||||
|
def let_one_day_pass(self, run_time = 2):
|
||||||
|
all_creatures = self.get_pi_creatures()
|
||||||
|
on_screen_creatures = self.get_on_screen_pi_creatures()
|
||||||
|
low_i = len(on_screen_creatures)
|
||||||
|
high_i = min(2*low_i, len(all_creatures))
|
||||||
|
new_creatures = VGroup(*all_creatures[low_i:high_i])
|
||||||
|
|
||||||
|
to_children_anims = []
|
||||||
|
growing_anims = []
|
||||||
|
for old_pi, pi in zip(on_screen_creatures, new_creatures):
|
||||||
|
pi.save_state()
|
||||||
|
child = pi.copy()
|
||||||
|
child.scale(0.25, about_point = child.get_bottom())
|
||||||
|
child.eyes.scale(1.5, about_point = child.eyes.get_bottom())
|
||||||
|
pi.move_to(old_pi)
|
||||||
|
pi.set_fill(opacity = 0)
|
||||||
|
|
||||||
|
index = list(new_creatures).index(pi)
|
||||||
|
prop = float(index)/len(new_creatures)
|
||||||
|
alpha = np.clip(len(new_creatures)/8.0, 0, 0.5)
|
||||||
|
rate_func = squish_rate_func(
|
||||||
|
smooth, alpha*prop, alpha*prop+(1-alpha)
|
||||||
|
)
|
||||||
|
|
||||||
|
to_child_anim = Transform(pi, child, rate_func = rate_func)
|
||||||
|
to_child_anim.update(1)
|
||||||
|
growing_anim = ApplyMethod(pi.restore, rate_func = rate_func)
|
||||||
|
to_child_anim.update(0)
|
||||||
|
|
||||||
|
to_children_anims.append(to_child_anim)
|
||||||
|
growing_anims.append(growing_anim)
|
||||||
|
|
||||||
|
time = self.t_expression[-1]
|
||||||
|
total_new_creatures = len(on_screen_creatures) + len(new_creatures)
|
||||||
|
new_time = TexMobject(str(int(np.log2(total_new_creatures))))
|
||||||
|
new_time.move_to(time, LEFT)
|
||||||
|
|
||||||
|
growing_anims.append(Transform(time, new_time))
|
||||||
|
|
||||||
|
self.play(*to_children_anims, run_time = run_time/2.0)
|
||||||
|
self.play(*growing_anims, run_time = run_time/2.0)
|
||||||
|
|
||||||
|
def get_num_pi_creatures_on_screen(self):
|
||||||
|
mobjects = self.get_mobjects()
|
||||||
|
return sum([
|
||||||
|
pi in mobjects for pi in self.get_pi_creatures()
|
||||||
|
])
|
||||||
|
|
||||||
|
def get_population_size_descriptor(self):
|
||||||
|
on_screen_creatures = self.get_on_screen_pi_creatures()
|
||||||
|
brace = Brace(on_screen_creatures, LEFT)
|
||||||
|
n = len(on_screen_creatures)
|
||||||
|
label = brace.get_text(
|
||||||
|
"$2^%d$"%int(np.log2(n)),
|
||||||
|
"$=%d$"%n,
|
||||||
|
)
|
||||||
|
brace.add(label)
|
||||||
|
return brace
|
||||||
|
|
||||||
|
def get_num_days(self):
|
||||||
|
x, y = self.pi_creature_grid_dimensions
|
||||||
|
return int(np.log2(x*y))
|
||||||
|
|
||||||
|
def get_curr_day(self):
|
||||||
|
return int(np.log2(len(self.get_on_screen_pi_creatures())))
|
||||||
|
|
||||||
|
def get_from_day_to_day_label(self):
|
||||||
|
curr_day = self.get_curr_day()
|
||||||
|
top_words = TextMobject(
|
||||||
|
"From day", str(curr_day),
|
||||||
|
"to", str(curr_day+1), ":"
|
||||||
|
)
|
||||||
|
top_words.scale_to_fit_width(4)
|
||||||
|
top_words.next_to(
|
||||||
|
self.function, DOWN,
|
||||||
|
buff = MED_LARGE_BUFF,
|
||||||
|
aligned_edge = LEFT,
|
||||||
|
)
|
||||||
|
top_words[1].highlight(GREEN)
|
||||||
|
|
||||||
|
bottom_words = TexMobject(
|
||||||
|
str(2**curr_day),
|
||||||
|
"\\text{ creatures}", "\\over {1 \\text{ day}}"
|
||||||
|
)
|
||||||
|
bottom_words[0].highlight(GREEN)
|
||||||
|
bottom_words.next_to(top_words, DOWN, buff = MED_LARGE_BUFF)
|
||||||
|
|
||||||
|
return top_words, bottom_words
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -325,6 +325,16 @@ class Scene(object):
|
||||||
self.add_frames(*[self.get_frame()]*int(duration / self.frame_duration))
|
self.add_frames(*[self.get_frame()]*int(duration / self.frame_duration))
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
def force_skipping(self):
|
||||||
|
self.original_skipping_status = self.skip_animations
|
||||||
|
self.skip_animations = True
|
||||||
|
return self
|
||||||
|
|
||||||
|
def revert_to_original_skipping_status(self):
|
||||||
|
if hasattr(self, "original_skipping_status"):
|
||||||
|
self.skip_animations = self.original_skipping_status
|
||||||
|
return self
|
||||||
|
|
||||||
def add_frames(self, *frames):
|
def add_frames(self, *frames):
|
||||||
self.frames += list(frames)
|
self.frames += list(frames)
|
||||||
|
|
||||||
|
|
|
@ -346,10 +346,12 @@ class PiCreatureScene(Scene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"total_dither_time" : 0,
|
"total_dither_time" : 0,
|
||||||
"seconds_to_blink" : 3,
|
"seconds_to_blink" : 3,
|
||||||
|
"pi_creatures_start_on_screen" : True,
|
||||||
}
|
}
|
||||||
def setup(self):
|
def setup(self):
|
||||||
self.pi_creatures = VGroup(*self.create_pi_creatures())
|
self.pi_creatures = VGroup(*self.create_pi_creatures())
|
||||||
self.add(*self.pi_creatures)
|
if self.pi_creatures_start_on_screen:
|
||||||
|
self.add(*self.pi_creatures)
|
||||||
|
|
||||||
def create_pi_creatures(self):
|
def create_pi_creatures(self):
|
||||||
"""
|
"""
|
||||||
|
@ -367,6 +369,17 @@ class PiCreatureScene(Scene):
|
||||||
def get_primary_pi_creature(self):
|
def get_primary_pi_creature(self):
|
||||||
return self.pi_creatures[0]
|
return self.pi_creatures[0]
|
||||||
|
|
||||||
|
def any_pi_creatures_on_screen(self):
|
||||||
|
mobjects = self.get_mobjects()
|
||||||
|
return any([pi in mobjects for pi in self.get_pi_creatures()])
|
||||||
|
|
||||||
|
def get_on_screen_pi_creatures(self):
|
||||||
|
mobjects = self.get_mobjects()
|
||||||
|
return VGroup(*filter(
|
||||||
|
lambda pi : pi in mobjects,
|
||||||
|
self.get_pi_creatures()
|
||||||
|
))
|
||||||
|
|
||||||
def introduce_bubble(
|
def introduce_bubble(
|
||||||
self,
|
self,
|
||||||
pi_creature,
|
pi_creature,
|
||||||
|
@ -434,7 +447,7 @@ class PiCreatureScene(Scene):
|
||||||
first mobject being animated with each .play call
|
first mobject being animated with each .play call
|
||||||
"""
|
"""
|
||||||
animations = Scene.compile_play_args_to_animation_list(self, *args)
|
animations = Scene.compile_play_args_to_animation_list(self, *args)
|
||||||
if not any([pi in self.get_mobjects() for pi in self.get_pi_creatures()]):
|
if not self.any_pi_creatures_on_screen():
|
||||||
return animations
|
return animations
|
||||||
|
|
||||||
non_pi_creature_anims = filter(
|
non_pi_creature_anims = filter(
|
||||||
|
@ -473,11 +486,34 @@ class PiCreatureScene(Scene):
|
||||||
return animations
|
return animations
|
||||||
|
|
||||||
def blink(self):
|
def blink(self):
|
||||||
self.play(Blink(random.choice(self.get_pi_creatures())))
|
self.play(Blink(random.choice(self.get_on_screen_pi_creatures())))
|
||||||
|
|
||||||
|
def joint_blink(self, pi_creatures = None, shuffle = True, **kwargs):
|
||||||
|
if pi_creatures is None:
|
||||||
|
pi_creatures = self.get_on_screen_pi_creatures()
|
||||||
|
creatures_list = list(pi_creatures)
|
||||||
|
if shuffle:
|
||||||
|
random.shuffle(creatures_list)
|
||||||
|
|
||||||
|
def get_rate_func(pi):
|
||||||
|
index = creatures_list.index(pi)
|
||||||
|
proportion = float(index)/len(creatures_list)
|
||||||
|
start_time = 0.8*proportion
|
||||||
|
return squish_rate_func(
|
||||||
|
there_and_back,
|
||||||
|
start_time, start_time + 0.2
|
||||||
|
)
|
||||||
|
|
||||||
|
self.play(*[
|
||||||
|
Blink(pi, rate_func = get_rate_func(pi), **kwargs)
|
||||||
|
for pi in creatures_list
|
||||||
|
])
|
||||||
|
return self
|
||||||
|
|
||||||
def dither(self, time = 1, blink = True):
|
def dither(self, time = 1, blink = True):
|
||||||
while time > 0:
|
while time > 0:
|
||||||
if blink and self.total_dither_time%self.seconds_to_blink == 0:
|
time_to_blink = self.total_dither_time%self.seconds_to_blink == 0
|
||||||
|
if blink and self.any_pi_creatures_on_screen() and time_to_blink:
|
||||||
self.blink()
|
self.blink()
|
||||||
else:
|
else:
|
||||||
Scene.dither(self)
|
Scene.dither(self)
|
||||||
|
|
Loading…
Add table
Reference in a new issue