Плавная анимация
Прогресс анимации
Любая анимация — это значение, которое меняется со временем. Удобнее всего считать прогресс p — долю пройденного, от 0 до 1:
p = (t - start) / duration
p = max(0, min(1, p)) # до начала — 0, после конца — 1
Ограничение обязательно: без него до начала анимации получится отрицательное значение, а после конца — больше единицы.
Интерполяция
По прогрессу находят текущее значение между начальным и конечным — линейная интерполяция (lerp):
def lerp(a, b, p):
return a + (b - a) * p
label.opacity = int(lerp(0, 255, p)) # проявление
ball.x = lerp(100, 700, p) # движение
У фигур и надписей pyglet есть opacity — прозрачность от 0 (невидимо) до 255; а также color, x, y, rotation, scale у спрайтов. Всё это можно анимировать.
Функции плавности
Если подставлять p напрямую, движение равномерное и выглядит механически. Функция плавности (easing) переделывает прогресс:
def ease_in(p): # медленный старт
return p * p
def ease_out(p): # медленный финиш
return 1 - (1 - p) ** 2
def ease_in_out(p): # разгон и торможение
if p < 0.5:
return 2 * p * p
return 1 - (2 - 2 * p) ** 2 / 2
ball.x = lerp(100, 700, ease_in_out(p))
У всех функций плавности f(0) = 0 и f(1) = 1 — начало и конец не меняются, меняется только «характер» движения между ними.
Ключевые кадры
Сложную анимацию описывают ключевыми кадрами — значениями в отдельные моменты:
X_KEYS = [(0, 100), (1.5, 650), (2.5, 650), (4, 100)] # (время, x)
Чтобы найти значение в момент t, ищут пару соседних кадров t0 ≤ t < t1 и интерполируют между ними с прогрессом (t - t0) / (t1 - t0). До первого кадра берут его значение, после последнего — значение последнего.
Два кадра с одинаковым временем — мгновенный скачок. Делить на ноль при этом нельзя, поэтому такой «отрезок» нулевой длины пропускают.
Итог
- прогресс
p = (t - start) / duration, ограниченный отрезком от 0 до 1; lerp(a, b, p); анимировать можноx,y,opacity,color,radius…;- easing:
ease_in,ease_out,ease_in_out— f(0) = 0, f(1) = 1; - ключевые кадры: найти отрезок и интерполировать; скачок — два кадра с одним временем.