Риг Mario в один Null

Стояла задача сделать модификацию геймплея Super Mario Bros.:

https://www.behance.net/gallery/57524839/DOTA-2-in-Super-Mario-Bros

Еще пара гифок и версия со звуком по клику

Вариант анимации руками был отметен сразу (хотя в комментариях на реддит читал мнение, что это покадровая анимация).

Возможно проще было собрать подобное в каком-нибудь Unity, там и анимировать потом меньше пришлось бы, но я знаю только выражения After Effects:

Начнем с нуля

Любой проект начинается с композиции.
У нас тут пиксель арт, поэтому 200х150 будет достаточно.
FPS не особо важен, пускай будет 24.

 

 

Самое время создать Null Object, на котором все и будет завязано.
Немного подготовки:

  1. Переименовываем Null в Contol;
  2. Меняем размер до 16х16;
  3. Перемещаем Anchor Point в центр (Ctrl+Alt+Home);
  4. Заново центрируем (Ctrl+Home);

И сразу добавим окружение:

Прыжок

Добавим нашего героя в композицию.

Для начала хватит двух спрайтов: Mario_Static и Mario_Jump.

 

 

Кидаем их в композицию (центрируй спрайты (Ctrl+Home), если они оказались не в центре композиции) и привязываем к Control’у.

Теперь перемещая Control все спрайты Марио будут перемещаться вместе с ним.

Дело за малым: научить их самих определять когда показываться.

 

Чтобы пиксели не смешивались в промежуточных позициях слой нужно переключить в режим пикселизации. Актуально для всех слоев в этом проекте, больше напоминать не буду.

 

Разместим Control так, чтоб Марио как бы стоял на земле.

Видимость Mario_Jump можно пока выключить, чтобы лишние конечности нас не отвлекали, только не забудь включить потом.

Для того, чтобы Марио понимал, когда он в прыжке, а когда на земле нужно эту землю как-то определять. Самый простой способ – задать ее уровень в ручную, благо менять часто не придется.

Добавим на Control эффект Slider Control и назовем Land level. А в значение скопипастим yPosition Control’а (сейчас он находится как раз на уровне земли).

Теперь добавим еще один Slider Control. Назовем его [Mario] (квадратные скобки я использую в случае значений, которые задаются выражениями) и через Land level зададим его значение:

* y < Land, потому что чем точка выше по y, тем значение y будет меньше

Осталось задать непрозрачность спрайтов через значение этого слайдера.

Для Mario_Jump это будет:

А для Mario_Static:


Итак, Марио умеет прыгать, научим же его бегать!

Также в Position Control’а можно написать выражение, чтобы Марио как бы упирался в землю и не уходил ниже ее уровня:

Но вообще говоря оно лишнее и даже может испортить анимацию в некоторых случаях, поэтому просто поверь, что оно не нужно.

Бег

Бег это цикличная серия спрайтов, поэтому для удобства объединим их в один слой. Создаем композицию Mario_Run длительностью в три кадра и располагаем спрайты бега друг за другом.

Вместо трех кадров можно создать композицию в 6 кадров, а каждый спрайт растянуть на два кадра, так Марио будет перебирать ножками медленнее.

Закидываем композицию Mario_Run в нашу композицию, привязываем к Controlу и копируем позицию у другого слоя с Марио.

Залупим анимацию бега, для этого в Time Remap (Ctrl+Alt+T) прописываем loopOut(), и т.к. это композиция, то фиксим цикл создав ключ перед последним ключом, а затем копируя первый ключ на место последнего.

Итак, слой Mario_Run должен быть виден при следующих условиях:

  • Марио находится в движении
  • Марио не в прыжке

Для того, чтобы узнать в движении ли Марио воспользуемся командой position.speed.

В дальнейшем удобно будет наблюдать значение скорости перед глазами, поэтому создадим отдельный Slider Control под это дело (обещаю, что это последний).

Называем новый слайдер [Speed] и прописываем в него, собственно:

Теперь можем дополнить [Mario]:

А в непрозрачность Mario_Run напишем:

И тут мы можем наглядно наблюдать странный баг (актуален на CC 2017.2): Если y не меняется, но при этом меняется x, то в некоторых кадрах AE считает, что y тоже меняется:

Вот этог Марио движется только по x, откуда же эти неожиданные  ̶з̶и̶г̶и̶  прыжки?

В общем, поиск и решение проблемы стоили мне нервов (знаете эти моменты, когда 2х2 получается 5 и “ДА КАК ТАК-ТО?!”), но вам оно достанется прямо сейчас:

Также необходимо обновить выражение скорости (слайдер [Speed]) с position.speed на transform.xPosition.speed.

Всё, теперь yPosition и xPosition это разные свойства и y не будет псевдо-меняться от изменений x.
А еще так анимировать Марио удобнее, можно, кстати, уже затестить.

Заодно сотрем несколько блоков, с ямой-то веселее!

Для красивой анимации используйте временную интерполяцию ключей:

  • по x: Out на 20;
  • по y: в верхней точке прыжка In/Out на 50.

Удобно делать интерполяцию не графиками, а ползунками в какой-нибудь сторонней панельке, например Motion 2.

Осталось научить Марио разворачиваться.

Разворот

Зеркальное отображение всех спрайтов легко сделать добавив следующее выражение на Scale Control’а:

В принципе на этом уже можно закончить, но я добавил еще Mario_Turn.

Уже привычно закидываем в композицию, привязываем к Control’у и копипастим Position с другого спрайта.

Mario_Turn должен быть виден во время смены направления движения и за два кадра до этого. Другими словами нам нужно отследить момент, когда Scale меняет значение.

Исходя из этих выводов проапгрейдим слайдер [Mario]:

Mario_Turn имеет больший приоритет, чем Mario_Run, поэтому строку возвращающую 3 ставим раньше;

thisComp.frameDuration — длительность кадра композиции;
time+3*thisComp.frameDuration — текущее время + три кадра;
valueAtTime(time+3*thisComp.frameDuration) — взять значение в момент времени ()

Ну и для непрозрачности Mario_Turn уже классическое выражение:

Теперь положения Control’а влияет на то какой спрайт будет отображаться, а направление движения на то куда смотрит Марио.

Готовый проект можно найти тут.

И можете подписаться на мой Telegram-канал.