- PVSM.RU - https://www.pvsm.ru -

Всем привет!
Рождество давно прошло, но после него у нас осталась занимательная история о том, как при помощи нечасто используемой возможности Core Animation можно создать пользователям праздничное настроение. Делюсь переводом статьи моего лондонского коллеги Алексиса.
Рождество всегда было для меня одним из самых любимых дней в году. Оно приносит в наши жизни много любви, смеха, счастья и волшебства.
Я родился и вырос в Испании, на Тенерифе — солнечном острове посреди Атлантического океана недалеко от побережья Африки. И, поверьте мне, Рождество на Тенерифе сильно отличается от Рождества в Лондоне, где я встречал его последние два года (с тех пор как начал работать в Badoo).
Одним из преимуществ жизни в Лондоне для меня стало созерцание снежинок. Здесь я увидел их впервые в жизни, это было просто невероятно!
Вспомнив об этом, я решил поделиться с вами одной интереснейшей историей, случившейся со мной в офисе незадолго до Рождества, перед тем как я отправился на Тенерифе, чтобы встретить праздник со своей семьёй.
Так уж случилось, что мне поручили одну необычную задачу со следующим описанием:

Хм, довольно занятно. Мы хотели добавить рождественскую анимацию со снежинками в наше iOS-приложение, и я стал тем счастливчиком, который должен был её создать. Но я не знал, с чего начать.
Как обычно, к задаче был прилинкован Sketch-файл c необходимым дизайном, который выглядел примерно так:

Как минимум я видел, что нам требуется, но не был до конца уверен, как эти снежинки должны себя вести. Чтобы прояснить все детали, я отправился общаться с дизайнерами.
Как я и подозревал, у них уже была готова великолепная анимация, нарисованная в After Effects [1].
Дизайнеры объяснили мне, что хотят добавить падающие сверху снежинки в уже существующую анимацию запуска приложения (а также шапку Санты на наш логотип, но это была простая подмена картинки, недостойная упоминания в этой статье).
Я знал, что анимация запуска приложения на iOS сделана с помощью Lottie [2], так как её добавили уже после того, как я присоединился к компании (подробности можно найти в статье Radek Cieciwa [3]). Однако я сказал дизайнерам, что попробую найти более простые решения для показа снежинок (без необходимости использовать Lottie) — и начал исследовать различные подходы.
Вот такую анимацию мой коллега Radek сделал для Badoo. Безупречно!

А вот так я добавил падающие снежинки. Хотите знать, как у меня это получилось? Ответ вы найдёте ниже.

Во время чтения различной документации про анимации я вспомнил о том, что в играх и фильмах для решения подобных задач довольно часто используют системы частиц.
«Википедия [4]» описывает это понятие довольно точно:
«Систе́ма части́ц — используемый в компьютерной графике способ представления объектов, не имеющих чётких геометрических границ (различные облака, туманности, взрывы, струи пара, шлейфы от ракет, дым, снег, дождь и т. п.). Системы частиц могут быть реализованы как в двумерной, так и в трёхмерной графике».
Система частиц состоит из одного или нескольких графических примитивов, таких как точки, линии или изображения, именуемых частицами. Эти частицы создаются и испускаются эмиттером, являющимся частью системы частиц.
Каждая частица обладает набором параметров, которые прямо или косвенно влияют на её поведение и определяют то, как она будет отрисована. Частицы могут двигаться одновременно в большом количестве и в различных направлениях, например для создания эффекта жидкости.
Анимация начинает действовать, когда частицы испускаются системой. Система испускает частицы в случайных местах в рамках заданной системой частиц области. Она может принимать различные формы: круг, прямоугольник, сфера, параллелепипед, линия, точка и т. д.
Система также определяет свойства частиц, влияющие на их геометрию, скорость и другие параметры. Разные API для работы с эмиттером имеют разные названия схожих свойств.
Когда частицы испускаются системой одновременно, они создают ошеломляющие анимации, которые могут выглядеть как дождь, огонь или снег.

Я подумал, что Apple, скорее всего, имеет встроенную поддержку системы частиц в одном из своих фреймворков. И результаты моих поисков показали, что я прав.
Система частиц является частью фреймворка Core Animation и хорошо описана в классах CAEmitterLayer [5] и CAEmitterCell [6].
После изучения всей необходимой информации о системе частиц и поддерживаемых API на iOS я приступил к моей любимой части — реализации нашей задумки.
К несчастью, Рождество не вечно, поэтому нам нужна была возможность отключить снежинки удалённо после 25 декабря.
Как я упомянул выше, анимация запуска приложения была реализована с помощью Lottie. То есть мне нужно было найти способ добавить снежинки таким образом, чтобы это не затрагивало существующую анимацию и её код, потому что моё решение должно было быть удалено сразу после релиза.
Я нашёл очень простой способ это сделать — добавил новый прозрачный UIView для показа снежинок перед существующей анимацией и фоном и затем контролировал его появление удалённо с помощью флага.

Изображение выше показывает UIView, которые были использованы в финальном решении:
После того как эта проблема была решена, мне оставалось создать компонент, содержащий логику испускания частиц для генерации анимированных снежинок.
Для начала мне были необходимы изображения снежинок, которые я мог бы использовал в качестве контента для эмиттера. Они должны быть довольно простыми, не так ли?
Каждая снежинка представляла собой либо обычный, либо размытый белый круг. Я создал их самостоятельно в программе Sketch.

CAEmitterLayer — это специальный CALayer, который создаёт, анимирует и отрисовывает систему частиц. Он позволяет контролировать свою геометрию, позицию, режим отрисовки и многое другое.
Я начал разработку анимации с создания слоя:
snowEmitterLayer.emitterShape = CAEmitterLayerEmitterShape.line
snowEmitterLayer.beginTime = CACurrentMediaTime()
snowEmitterLayer.timeOffset = 10.0
Мне нужно было изменить только три свойства:
Имея готовый слой, я создал два разных эмиттера: для снежинок потяжелее и для снежинок полегче.
Для тяжёлых снежинок я настроил эмиттер следующим образом:
let flakeEmitterCell = CAEmitterCell()
flakeEmitterCell.contents = UIImage(named: "snowflake_dot")!.cgImage
flakeEmitterCell.emissionRange = .pi
flakeEmitterCell.lifetime = 20.0
flakeEmitterCell.birthRate = 30
flakeEmitterCell.scale = 0.15
flakeEmitterCell.scaleRange = 0.6
flakeEmitterCell.velocity = 30.0
flakeEmitterCell.velocityRange = 20
flakeEmitterCell.spin = -0.5
flakeEmitterCell.spinRange = 1.0
flakeEmitterCell.yAcceleration = 30.0
flakeEmitterCell.xAcceleration = 5.0
Как видите, мне пришлось изменить значительное количество свойств, каждое из которых очень важно для достижения желаемого эффекта:
Мне также понадобился второй эмиттер для создания лёгких снежинок. Все свойства остались без изменений, за исключением двух:
let blurryFlakeEmitterCell = CAEmitterCell()
blurryFlakeEmitterCell.contents = UIImage(named: "snowflake_blurry_dot")?.cgImage
blurryFlakeEmitterCell.velocity = 40
// Остальные свойства остались без изменений
Мне оставалось только соединить слой и эмиттеры, что оказалось очень легко:
snowEmitterLayer.emitterCells = [flakeEmitterCell, blurryFlakeEmitterCell]
self.layer.addSublayer(snowEmitterLayer)
Я довольно быстро создал рабочий вариант с падающими снежинками, который выглядел очень неплохо. Он был довольно прост в реализации и не менял существующего кода. Я показал его дизайнерам, и он им очень понравился.
Анимации, созданные с помощью системы частиц, могут быть довольно впечатляющими и относительно простыми в реализации, если вы владеете правильными инструментами.
Больше информации о системах частиц вы найдёте в следующих источниках:
Автор: Щукин Антон
Источник [10]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/ios-development/313690
Ссылки в тексте:
[1] After Effects: https://www.adobe.com/uk/products/aftereffects.html
[2] Lottie: https://github.com/airbnb/lottie-ios
[3] Radek Cieciwa: https://badoo.com/techblog/blog/2017/07/12/behind-the-scenes-with-importing-adobe-after-effects-animation-into-badoo-ios-app/
[4] Википедия: https://en.wikipedia.org/wiki/Particle_system
[5] CAEmitterLayer: https://developer.apple.com/documentation/quartzcore/caemitterlayer
[6] CAEmitterCell: https://developer.apple.com/documentation/quartzcore/caemittercell
[7] Ray Wenderlich: https://www.raywenderlich.com/1255-scene-kit-tutorial-with-swift-part-5-particle-systems
[8] Unity: https://docs.unity3d.com/Manual/PartSysWhatIs.html
[9] Allen Martin on particle systems: https://web.cs.wpi.edu/~matt/courses/cs563/talks/psys.html
[10] Источник: https://habr.com/ru/post/446938/?utm_source=habrahabr&utm_medium=rss&utm_campaign=446938
Нажмите здесь для печати.