Автор оригинала: FreeCodeCamp Community Member.
Nash Vail.
В традиционной (рисованной) анимации старший или ключевой артист рисует ключевые кадры, которые определяют движение.
Помощник, вообще стажер или младший художник, затем рисует необходимые Inbetweens для сцены. Работа помощника, также называемой Inbetweener, заключается в том, чтобы переходы между ключевыми позами выглядят гладкими и естественными.
Inbetweens необходимы, поскольку анимации без них кажутся измельчивыми. К сожалению, рисунок в бетахрене – это более или менее грузоподъемность. Но это двадцать первый век, и у нас есть компьютеры, которые могут обрабатывать этот тип задачи.
Помните, что учителя сказали вам в класс школе о компьютерах глупыми? Компьютеры должны быть сказаны точной последовательности шагов для выполнения действия. Сегодня мы посмотрим на одну такую последовательность шагов, или алгоритм, что помогает компьютеру привлечь необходимые Inbetweens для создания гладкой анимации.
Я буду использовать HTML5 Canvas и JavaScript, чтобы проиллюстрировать алгоритм. Тем не менее, вы сможете прочитать и понять статью, даже если вы не знакомы с ними.
Намерение
Наша цель проста, чтобы оживить мяч из пункта A (Startx, Starty)
до b (Endx, Endy)
Отказ
Если эта сцена была передана в студию, которая делает традиционную анимацию, старший художник будет нарисовать следующие ключевые позы …
… а затем пройдите доску на чертежей к младшему художнику, чтобы нарисовать, как так.
Для нашей ситуации нет анимационной студии и у нас есть младшие художники. Все, что у нас есть, это цель, компьютер и способность писать какой-то код.
Подход
HTML-код прост, нам нужна только одна строка.
Эта часть кода JavaScript (показана ниже) просто захватывает
const canvas = document.getElementById('canvas'), context = canvas.getContext('2d'), width = canvas.width = window.innerWidth, height = canvas.height = window.innerHeight;
Функция ниже рисует зеленый твердый круг радиуса Радиус
на х
и y
координаты.
function drawBall(x, y, radius) { context.beginPath(); context.fillStyle = '#66DA79'; context.arc(x, y, radius, 0, 2 * Math.PI, false); context.fill();}
Все вышеуказанному коду является Boilerplate для настройки нашей анимации, вот сочная часть.
// Point Alet startX = 50, startY = 50;
// Point Blet endX = 420, endY = 380;
let x = startX, y = startY;
update();function update() { context.clearRect(0, 0, width, height); drawBall(x, y, 30); requestAnimationFrame(update);}
Прежде всего, обратите внимание на Обновить
Функция называется прямо над его декларацией. Во-вторых из всего, уведомление ProwelsimationFrame (Обновление)
который звонит Обновить
неоднократно Отказ
Флипбук анимация – хорошая аналогия для такого рода программы, которую мы пишете. Так же, как неоднократно переворачивается через флипбук, создает иллюзию движения, неоднократно называя Обновить
Функция создает иллюзию движения для нашего зеленого шара.
Одно следует отметить, что код выше, состоит в том, что «Обновление» – это просто имя. Функция могла быть названа чем-то еще. Некоторые программисты, как имена NextFrame
, петля
, рисовать
или Флип
Потому что функция неоднократно называется. Важная часть – это то, что делает функция.
На каждом последующем вызове Обновить
Мы ожидаем, что функция нарисовать немного другое изображение на холсте, чем предыдущий.
Наша текущая реализация Обновить
Рисует мяч в той же точной позиции на каждом звонке Вытягивание (X, Y, 30)
Отказ Нет анимации, но давайте изменим это. Ниже есть ручка Это содержит код, который мы написали до сих пор, вы можете открыть его и следовать.
На каждой итерации Обновить
Давайте пойдем вперед и увеличиваем ценность х
и y
и посмотреть, как анимация это создает.
function update() { context.clearRect(0, 0, width, height); drawBall(x, y, 30); x++; y++; requestAnimationFrame(update);}
Каждая итерация перемещает мяч вперед как в направлениях X, так и Y, и повторные вызовы Обновить
приводит к анимации, как показано на рисунке.
Хотя сделка, наша цель заключалась в том, чтобы переместить мяч из начального положения к Конечная позиция Отказ Но мы ничего не делаем абсолютно о том, чтобы остановить мяч в конечном положении. Давайте исправить это.
Одно очевидное решение состоит в том, чтобы увеличить только координаты, когда они меньше, чем endx
и Энди
значения. Таким образом, как только мяч пересекает Endx, Endy
Его координаты прекратит обновление, а мяч остановится.
function update() { context.clearRect(0, 0, width, height); drawBall(x, y, 30); if(x <= endX && y <= endY) { x++; y++; } requestAnimationFrame(update);}
В этом подходе есть ошибка. Вы видите это?
Проблема вот что вы не можете сделать мяч добраться до любой Конечная координата вы хотите, просто увеличивая х
и y
Значения по 1
Отказ Например, рассмотреть конечные координаты (500, 500)
, конечно, если вы начнете в (0, 0)
и добавить 1
к х
и y
они в конечном итоге доберутся до (500, 500)
Отказ Но что, если я выбрал (432, 373)
как координаты координат?
Используя вышеуказанный подход, вы можете добраться только к точкам, лежащим в прямой линии 45 градусов от горизонтальной оси.
Теперь вы можете использовать тригонометрию и причудливую математику, чтобы рассчитать точные суммы, которые х
и y
должны быть увеличены, чтобы достичь любой координаты, которую вы хотите. Но вам не нужно делать это, когда у вас есть линейная интерполяция.
Подход с линейной интерполяцией
Вот какая линейная функция интерполяции A.K.A lerp
выглядит как.
function lerp(min, max, fraction) { return (max — min) * fraction + min;}
Чтобы понять, какая линейная интерполяция считает слайдер с мин
Значение на левом конце и Макс
Значение на правом конце.
Следующее, что нам нужно выбрать Фракция
Отказ lerp
берет Фракция
и преобразует, что на значение между мин
и Макс
Отказ
Когда я поставил 0,5
В lerp
Формула – нет сюрпризов – она переводится на 50. Это именно точка на полпути между 0
(мин) и 100
(Максимум).
Точно так же, если мы выберем другое значение для Фракция
Скажи 0,85
…
И если мы позвольте Фракция
, lerp
будет выводить 0
(мин) и на Фракция
, lerp
будет производить 100
(Максимум).
Я выбрал 0 и 100, как мин
и Макс
Чтобы сохранить этот пример простой, но lerp
Будет работать для любого произвольного выбора мин
и Макс
Отказ
Для значений Фракция
между 0
и 1
, lerp
позволяет вам Интерполировать между мин
и Макс
Отказ Или другими словами, пересекаем между мин
и Макс
Значения, где выбираете 0
для Фракция
ставит вас на мин
, выбирая 1
ставит вас на Макс
и для любого другого значения между 0
и 1
, пускает вас где угодно между мин
и Макс
Отказ Вы также можете увидеть мин
и Макс
Как ключевые позы, как в традиционной анимации, а lerp
выводит как Inbetweens ;-).
Хорошо, но что, если кто-то даст ценность за пределами границ 0
и 1
как Фракция
к lerp
? Вы видите формулу для lerp
чрезвычайно простой с большинством основных математических операций. Здесь нет никаких трюков или плохих ценностей, просто представьте, что расширение слайдера в обоих направлениях. Какое-либо значение для Фракция
поставляется, lerp
Будет ли производить логический результат. Мы не должны платить много думать с плохими ценностями здесь, хотя, о чем мы должны подумать, это то, как все это карты анимируют мяч.
Если вы следуете, идите вперед и измените Обновить
Функция соответствовать следующему коду. Также не забудьте добавить в lerp
Функция, которую мы определили в начале этого раздела.
function update() { context.clearRect(0, 0, width, height); drawBall(x, y, 30); x = lerp(x, endX, 0.1); y = lerp(y, endY, 0.1); requestAnimationFrame(update);}
Вот a ручка Из чего наша программа выглядит сейчас. Попробуйте щелкнуть:)
Гладко справа? Вот как lerp
помогает улучшить анимацию.
В коде обратите внимание на переменные х
и y
– которые изначально устанавливаются на startx
и starty
– Отметьте текущую позицию мяча в любом кадре. Также мой выбор 0,1
как Фракция
Это произвольно, вы можете выбрать любое дробное значение, которое вы хотите. Имейте в виду, что ваш выбор Фракция
влияет на скорость анимации.
В каждом раме х
и endx
принимаются как мин
и Макс
и интерполирован с 0,1
как Фракция
Чтобы получить новое значение для х
Отказ Точно так же y
и Энди
используются как мин
и Макс
Чтобы получить новое значение для y
Использование 0,1
как фракция.
Затем мяч нарисован на новичке (х, у)
координировать.
Эти шаги повторяются до х
становится endx
и y
становится Энди
В каком случае мин
Отказ Когда мин
и Макс
стать равным lerp
бросает точное одинаковое значение (мин/макс) для любых дальнейших кадров, таким образом останавливая анимацию.
И именно вы используете линейную интерполяцию, чтобы плавно анимировать мяч.
Эта короткая статья очень охватывает. Мы начали, определяя условия, как ключевые позы и Inbetweens. Затем мы попробовали тривиальный подход для рисования Inbetweens и заметил его ограничения. Наконец, с линейной интерполяцией мы смогли добиться нашего намерения.
Я надеюсь, что вся математика имела смысл вам. Не стесняйтесь играть с линейной интерполяцией еще больше. Эта статья была вдохновлена Рэйчел Смит ‘s пост на кодепене Отказ У поста Rachel есть еще много примеров, обязательно проверьте это.
Ищу больше? Я регулярно публикую на моем Блог на nashvail.me. Увидимся там, хорошего!