20 августа 2017

Процедурные анимации - 6

Сегодня поговорим об UI...
Дело в том, что обычно интерфейс действительно нагружен различными анимациями, переходами, подсвечиваниями и прочим... всё это нужно, чтобы пользователь ощущал своё взаимодействие с игрой и её интерфейсом.
Сделаем три несложные анимашки, а также я постараюсь показать, что все они могут быть использованы и для других целей.


Новый формат

Мне тут бахнуло в голову, что читать текст и разбираться в коде зачастую утомительно. Поэтому я стараюсь перейти на новый формат туторов - "всё в одной гифке". На мой взгляд так намного лучше усваивается информация. В общем, попробуем... если что - пишите в комментариях что нравится, а что - нет.

Твиттер

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

Простая анимация

Очень люблю этот пример. Я использую этот расширяющийся круг (см картинку внизу) постоянно. На кнопках, которые должны привлекать к себе внимание, на объектах, которые сообщаются о каком-то процессе. Например, заработали денег - и элемент со значением заработанных монет подмигивает. Или, как здесь, напоминаем о непрочитанном письме:


Немного пробегусь по коду. Здесь всего две строчки:

alpha = Math.cos(time * speed);
scale = Math.sin(time * speed) * 0.5 + 1;
  • Здесь переменная speed - это константа, изменяя значение которой, можно достичь медленной или, наоборот, очень быстрой анимации. 
  • Так как косинус и синус идут в противофазе, то получается, что в момент наибольшего размера прозрачность наименьшая. А нам это и нужно.
  • И ещё дополнительный трюк. В этом коде alpha принимает отрицательные значения. Во флеше, где я делал эту гифку, так устроено, что при alpha < 1 объект не рисуется. Если в вашем движке как-то иначе. То просто руками выставьте что-то подобное:
if(alpha < 0)
   alpha = 0;

Последовательное появление

Иногда нужна "связанная" анимация. То есть такая, при которой движение нескольких объектов связано между собой. Например, появление объектов друг за другом. Или же вращение по кругу всем вместе. В этом случае я использую одну формулу на всех, но при этом в саму формулу закладываю сдвиг для объектов. Например:

sprite[i].x = i;

В примере выше выходит, что координата каждого спрайта зависит от номера объекта в списке. Это очень удобно. Теперь сделаем также, но менять будем прозрачность:


Класс? Одна формула ведь, а можно всяких штук накрутить. Следы на песке, указатель для движения, различные индикаторы и прочее.
Итак, сама формула:

sprites[i].alpha = (1 + Math.cos(-i + time * 5)) / 2;

Трюки следующие:
  • Так как косинус принимает значения от -1 до 1, то мы прибавляем единицу, и получаем уже диапазон от 0 до 2. Делим пополам и в результате видим нужное нам от 0 до 1, чтобы потом присвоить альфе. Да, вот такую конструкцию (1 + cos() ) / 2 можно увидеть очень часто.
  • Вот этот вот -i как раз и есть "сдвиг по фазе", который и дает немного разные значения каждому спрайту в списке.
  • Ну и чтобы анимация ожила, включаем время в нашу формулу: time *5. Пятёрка - это скорость движения. Можно поиграться с этим значением и увидеть как цепочка побежит с разной скоростью.

Простой scale3 объект

Изменение простых параметров вроде позиции, прозрачности объекта или поворота обычно не составляет большой трудности. Другое дело, когда нужно изменить масштаб. С квадратом всё ок - как его не масштабируй, он всегда будет принимать форму прямоугольника. А вот со скруглённым квадратом всё иначе. 
Рисуем:



Масштабируем:


Вот такие артефакты лезут всегда при попытке масштабирования чего-то более сложного, чем обычный квадрат. Поэтому третий UI-эффект как раз посвящён подобной проблеме красивого масштабирования:



По-научному это называется scale3-объект. Ибо он разделен на три объекта, которые при правильном расположении позволяют масштабировать объект как угодно в одном направлении (горизонтальном, например).
Во многих движках такие объекты предусмотрены изначально. Просто передаем картинку и говорим "порежь её на части как надо". Но, на мой взгляд, всегда лучше понимать как что работает на самом базовом уровне. Зная, что на самом деле объект состоит из трёх картинок, вы всегда сможете реализовать именно то поведение, которое нужно в данной ситуации. Поэтому используйте scale3-объекты из вашего движка, но не забывайте как оно устроено внутри!

Кстати, при программировании движения нижних объектов на последней картинке я понял, что мне нужно поведение вроде "плавно сдвинулся, застыл... плавно сдвинулся обратно, застыл". Степенными функциями sin/cos такого достичь не получилось. Поэтому пришлось использовать tanh-функцию. Очень крутая на самом деле! Надо будет посвятить ей отдельный тутор...

Сообщения, схожие по тематике:

0 коммент.:

Отправить комментарий