核心动画中的粒子系统。 圣诞故事



大家好!

圣诞节已经过去很久了,但是在圣诞节之后,我们有一个有趣的故事,关于如何使用不常使用的Core Animation功能为用户营造节日气氛。 我分享伦敦同事亚历克西斯(Alexis)的文章翻译。

圣诞节一直是我一年中最喜欢的日子之一。 它给我们的生活带来了许多爱,欢笑,幸福和魔力。

我在西班牙特内里费岛(Tenerife)出生和长大,特内里费岛(Tenerife)是非洲海岸附近大西洋中间一个阳光明媚的岛屿。 而且,相信我,特内里费岛的圣诞节与伦敦的圣诞节有很大的不同,最近两年我在伦敦见到他(自从我开始在Badoo工作以来)。

对我来说,住在伦敦的好处之一就是考虑雪花。 在这里,我有生以来第一次见到他们,简直令人难以置信!

记住这一点,我决定在圣诞节前不久,在我去特内里费岛与家人庆祝假期之前,在办公室与我分享了一个有趣的故事。

碰巧的是,我被分配了一项不寻常的任务,其内容如下:



嗯,很有趣。 我们想将带有雪花的圣诞节动画添加到我们的iOS应用程序中,我很幸运地创建了它。 但是我不知道从哪里开始。

像往常一样,将草图文件附加到具有必要设计的任务上,如下所示:



至少我看到了我们所需要的,但是我不确定这些雪花应该如何表现。 为了弄清所有细节,我去与设计师交谈。

我怀疑,他们已经在After Effects中绘制了很棒的动画。

设计师向我解释说,他们希望将从上方飘落的雪花添加到启动该应用程序的现有动画中(以及徽标上的圣诞老人帽子,但这只是图片的简单替代,因此不值得在本文中提及)。

我知道在iOS上启动应用程序的动画是使用Lottie制作的 ,因为它是我加入公司后添加的(详细信息可以在Radek Cieciwa的文章中找到)。 但是,我告诉设计师,我将尝试找到用于显示雪花的更简单的解决方案(无需使用Lottie),并开始探索各种方法。

这是我的同事Radek为Badoo制作的动画。 无可挑剔!



因此,我添加了飘落的雪花。 想知道我是怎么做到的吗? 您将在下面找到答案。



粒子系统


在阅读有关动画的各种文档时,我记得在游戏和电影中,粒子系统通常用于解决此类问题。

维基百科非常准确地描述了这个概念:

“粒子系统是一种用于计算机图形学的方法,用于表示没有明确几何边界的对象(各种云,星云,爆炸,蒸汽射流,导弹列车,烟,雪,雨等)。 粒子系统可以在二维和三维图形中实现。”

该技术于1982年在《星际迷航2:可汗之怒》中首次使用,以产生“创世效应”。


粒子系统由一个或多个称为图元的图形图元(例如点,线或图像)组成。 这些粒子是由作为粒子系统一部分的发射器创建和发射的。

每个粒子都有一组直接或间接影响其行为并确定如何绘制的参数。 粒子可以同时在大量不同方向上同时移动,以产生液体效果。

当系统发射粒子时,动画才会生效。 系统会在粒子系统指定区域内的任意位置发射粒子。 它可以采用多种形式:圆形,矩形,球形,框形,线形,点形等。

该系统还确定影响其几何形状,速度和其他参数的粒子属性。 不同的发射器API对于相似的属性具有不同的名称。

当系统同时发射粒子时,它们会创建令人惊叹的动画,看起来像雨,火或雪。



从理论到实践


我认为苹果很可能在其框架之一中内置了粒子系统支持。 搜索结果表明我是对的。

粒子系统是Core Animation框架的一部分,并且在CAEmitterLayerCAEmitterCell类中进行了很好的描述。

在研究了有关iOS上的粒子系统和受支持的API的所有必要信息之后,我继续进行我最喜欢的部分-实现我们的想法。

不幸的是,圣诞节不会永远结束,因此我们需要能够在12月25日之后远程关闭雪花的功能。

如前所述,应用程序启动动画是使用Lottie实现的。 也就是说,我需要找到一种不影响现有动画及其代码的添加雪花的方法,因为我的解决方案必须在发行后立即删除。

我找到了一种非常简单的方法-添加了一个新的透明UIView,以在现有动画和背景前显示雪花,然后使用一个标记远程控制其外观。



上图显示了最终解决方案中使用的UIView:

  1. UIView带有发射雪花的粒子系统。
  2. Lottie驱动的应用程序启动动画中使用的UIViews。


解决此问题后,我必须创建一个包含粒子发射逻辑的组件以生成动画雪花。

首先,我需要可以用作发射器内容的雪花图像。 它们应该很简单,对吧?

每个雪花都是一个普通的或模糊的白色圆圈。 我自己在Sketch中创建了它们。



一些实施细节


CAEmitterLayer是一种特殊的CALayer,可创建,设置动画和渲染粒子系统。 它允许您控制几何形状,位置,绘图模式等等。

我开始通过创建图层来开发动画:

snowEmitterLayer.emitterShape = CAEmitterLayerEmitterShape.line snowEmitterLayer.beginTime = CACurrentMediaTime() snowEmitterLayer.timeOffset = 10.0 

我只需要更改三个属性:

  • itterShape :定义层的形状。 我使用了一条线,使雪花可以出现在整个屏幕上。
  • beginTime :是CAMediaTiming协议的一部分,表示相对于父层动画的层动画的开始时间;
  • timeOffset :也是CAMediaTiming协议的一部分,从本质上讲,它是相对于开始时间的给定时间的快速动画。 我将值指定为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 

如您所见,我必须更改大量属性,每个属性对于实现所需的效果都非常重要:

  • content:CGImage用来显示雪花(您记得,这是我自己创建的图像之一);
  • missionRange :以弧度表示的角度,定义了将在其中出现粒子的圆锥(我选择了PI角度,以便粒子在整个屏幕上可见);
  • 寿命 :确定一个粒子的寿命;
  • birthRate :确定每秒发射的粒子数;
  • scalescaleRange :影响粒子大小,最大大小为1.0; 间隔确定了所创建粒子之间的尺寸偏差,从而允许发射随机大小的粒子;
  • velocityvelocityRange :影响粒子出现的速度; 在velocityRange中指定的值内随机偏离;
  • spinspinRange :影响旋转速度(以弧度/秒为单位),并且在spinRange中指定的值内具有随机偏差;
  • yAccelerationxAcceleration :这是应用于发射器的加速度矢量的两个分量。

我还需要第二个发射器来产生雪花。 除以下两个以外,所有属性均保持不变:

  • 内容 :这里我使用了带有模糊圆圈的图像;
  • 速度 :在这里,我不得不降低下落的速度以使雪花变亮。

 let blurryFlakeEmitterCell = CAEmitterCell() blurryFlakeEmitterCell.contents = UIImage(named: "snowflake_blurry_dot")?.cgImage blurryFlakeEmitterCell.velocity = 40 //      

我只能连接图层和发射器,事实证明这很容易:

 snowEmitterLayer.emitterCells = [flakeEmitterCell, blurryFlakeEmitterCell] self.layer.addSublayer(snowEmitterLayer) 

结论


我很快创建了一个工作版本,雪花飘落,看起来非常好。 它非常容易实现,并且不会更改现有代码。 我向设计师展示了它,他们真的很喜欢它。

如果您拥有正确的工具,粒子系统动画可能会给人留下深刻的印象,并且相对容易实现。

有关粒子系统的更多信息可以在以下来源中找到:

Source: https://habr.com/ru/post/zh-CN446938/


All Articles