iOS:CAEmitterLayer粒子效果

栏目: IOS · 发布时间: 6年前

内容简介:说到粒子效果就要说到核心动画Core Animation,因为粒子效果所用到的特殊图层是包含在核心动画框架中的。这个特殊图层就是CAEmitterLayer。CAEmitterLayer是CALayer的一个常用子类,CALayer的子类有很多,CAEmitterLayer就是其中之一,CAEmitterLayer是用于实现基于Core Animation的高性能粒子引擎系统。粒子系统使用到两个类CAEmitterLayer与CAEmitterCell,CAEmitterLayer是粒子发射源,用来发射粒子

说到粒子效果就要说到核心动画Core Animation,因为粒子效果所用到的特殊图层是包含在核心动画框架中的。这个特殊图层就是CAEmitterLayer。

CAEmitterLayer是CALayer的一个常用子类,CALayer的子类有很多,CAEmitterLayer就是其中之一,CAEmitterLayer是用于实现基于Core Animation的高性能粒子引擎系统。

iOS:CAEmitterLayer粒子效果

粒子系统使用到两个类CAEmitterLayer与CAEmitterCell,CAEmitterLayer是粒子发射源,用来发射粒子的,它所发射的粒子就是CAEmitterCell(当然粒子也可以发射粒子,也就是CAEmitterCell也可以发射CAEmitterCell)。可以认为CAEmitterLayer是CAEmitterCell的发射源,通过不同的参数设置就会不断的产生不同的粒子。

我们首先来快速看一下这两个类的常用属性:

CAEmitterLayer常用属性

@property(nullable, copy) NSArray<CAEmitterCell *> *emitterCells; // 用来装粒子种类的数组, 通过给数组赋值,来支持多个cell
@property float birthRate; //粒子产生系数(倍数),默认1.0
@property float lifetime; // 粒子的生命周期系数, 默认1.0
@property CGPoint emitterPosition; // 决定粒子发射位置的中心点
@property CGFloat emitterZPosition; //三维立体中的位置
@property CGSize emitterSize; // 发射源的尺寸大小
@property CGFloat emitterDepth; // 发射源的深度
@property(copy) NSString *emitterShape; // 发射源的形状,默认是点point,(还有line,rectangle,circle,cuboid,sphere).
@property(copy) NSString *emitterMode; // 发射模式,默认是volume,(还有points,outline,surface).
@property(copy) NSString *renderMode; // 渲染模式,默认是unordered,还有oldestFirst,oldestLast,backToFront,additive
@property BOOL preservesDepth; //是否需要深度(一般使用这个属性)
@property float velocity; // 粒子基本速度系数, 默认1.0
@property float scale; // 粒子缩放比例系数, 默认1.0
@property float spin; // 粒子自旋转速度系数, 默认1.0
@property unsigned int seed; // 随机数发生器
复制代码

CAEmitterLayer里面的所有属性都在这里了,但是在实际情况中可能用不到这么多的属性,下面来重点介绍一些属性:

1. CAEmitterLayer控制发射源发射位置和形状的属性

  • emitterPosition:决定发射源的中心点
  • emitterSize: 决定发射源的大小
  • emitterShape:表示粒子从什么形状发射出来,它并不是表示粒子自己的形状。

emitterShape是一个枚举类型,提供如下类型可供选择:

  • kCAEmitterLayerPoint 点形状,发射源的形状就是一个点
  • kCAEmitterLayerLine 线形状,发射源的形状是一条线
  • kCAEmitterLayerRectangle 矩形状,发射源的形状是一个矩形
  • kCAEmitterLayerCuboid 立体矩形形状(3D),发射源是一个立体矩形,这里要生效的话需要设置z方向的数据,如果不设置就同矩形状.
  • kCAEmitterLayerCircle 圆形形状,发射源是一个圆形
  • kCAEmitterLayerSphere 立体圆形(3D),三维的圆形,同样需要设置z方向数据,不设置则如同二维的圆.
  • emitterMode:发射模式,它的作用其实就是进一步决定发射的区域是在发射形状的哪一部份。
  • kCAEmitterLayerPoints 点模式,发射器是以点的形式发射粒子。发射点就是形状的某个特殊的点,比如shap是一个点的话,那么这个点就是中心点,如果是圆形,那么就是圆心。
  • kCAEmitterLayerOutline 轮廓模式,从形状的边界上发射粒子。
  • kCAEmitterLayerSurface 表面模式,从形状的表面上发射粒子。
  • kCAEmitterLayerVolume 是相对于3D形状的物体内部发射.

我们用kCAEmitterLayerLine来说明一下。当你的CAEmitterLayer的emitterSize为CGSize(10, 10)时,你的所选择的emitterPosition为CGPoint(10,10)。那么形状为“Line”的CAEmitterLayer就会在如下图紫色的直线上产生粒子,对于“Line”来说,emitterSize的高度是被忽略的。

iOS:CAEmitterLayer粒子效果

我们可以这样理解,emitterPosition是所选emitterShape的中心点,例如对于矩形是对角线交点,对于圆形是圆心,对于直线是中点。而emitterSize则决定了矩形的大小,圆形的大小,直线的长度。 如果我把CAEmitterCell的速度属性全部设为0,此时没有速度的粒子就不会动了,再把发射模式emitterMode设为kCAEmitterLayerOutline,我们来看一下这几种发射形状的效果图:

iOS:CAEmitterLayer粒子效果
iOS:CAEmitterLayer粒子效果
iOS:CAEmitterLayer粒子效果
iOS:CAEmitterLayer粒子效果

现在我们利用同样的方法看下emitterMode的样式是什么样的,我们设置emitterShape发射形状为kCAEmitterLayerRectangle):

iOS:CAEmitterLayer粒子效果
iOS:CAEmitterLayer粒子效果
iOS:CAEmitterLayer粒子效果
  • renderMode : 渲染模式,决定了粒子是以怎么一种形式进行渲染的。
  • kCAEmitterLayerUnordered 粒子是无序出现的
  • kCAEmitterLayerOldestFirst 声明时间长的粒子会被渲染在最上层
  • kCAEmitterLayerOldestLast 声明时间短的粒子会被渲染在最上层
  • kCAEmitterLayerBackToFront 粒子的渲染按照Z轴的前后顺序进行
  • kCAEmitterLayerAdditive 进行粒子混合

2. CAEmitterLayer决定发射源粒子系数的属性

  • birthRate: 种类粒子产生系数,默认1.0;需要结合单个粒子cell的产生系数,每个粒子cell的产生系数乘以这个粒子产生系数,得出每秒具体产生粒子的个数。 即:每秒粒子产生个数 = layer.birthRate * cell.birthRate ;
  • lifetime:粒子的生命周期系数,默认1.0。
  • velocity:粒子速度系数, 默认1.0。
  • scale:粒子的缩放比例系数, 默认1.0。
  • spin:自旋转速度系数, 默认1.0。计算方式同上;

3.CAEmitterLayer决定发射源粒子内容的属性

emitterCells:用来装粒子的数组。每一种粒子就是一个CAEmitterCell。

CAEmitterCell常用属性

@property(nullable, copy) NSString *name; // 粒子名字, 默认为nil,有了名字才能找到对应的粒子
@property(getter=isEnabled) BOOL enabled; 
@property float birthRate; // 粒子的产生率,默认0
@property float lifetime; // 粒子的生命周期,默认0,以秒为单位。
@property float lifetimeRange; // 粒子的生命周期的范围,默认0,以秒为单位。
@property CGFloat emissionLatitude;// 指定纬度,纬度角代表了在x-z轴平面坐标系中与x轴与z轴之间的夹角,默认0
@property CGFloat emissionLongitude; // 指定经度,经度角代表了在x-y轴平面坐标系中与x轴与y轴之间的夹角,默认0
@property CGFloat emissionRange; //发射角度范围,默认0
@property CGFloat velocity; // 速度,默认是0
@property CGFloat velocityRange; //速度范围,默认是0
@property CGFloat xAcceleration; // 在x方向上的重力加速度分量,默认是0
@property CGFloat yAcceleration;// 在y方向上的重力加速度分量,默认是0
@property CGFloat zAcceleration;// 在z方向上的重力加速度分量,默认是0
@property CGFloat scale; // 粒子在生命周期范围内的缩放比例, 默认是1
@property CGFloat scaleRange; // 缩放比例范围,默认是0
@property CGFloat scaleSpeed; // 在生命周期内的缩放速度,默认是0,负数缩小,正数放大;
@property CGFloat spin; // 粒子的平均旋转速度,默认是0
@property CGFloat spinRange; // 自旋转角度范围,弧度制,默认是0
@property(nullable) CGColorRef color; // 粒子的颜色,默认白色
@property float redRange; // 粒子的颜色red,green,blue,alpha能改变的范围,默认0
@property float greenRange;
@property float blueRange;
@property float alphaRange;
@property float redSpeed; // 粒子速度red,green,blue,alpha在生命周期内的改变的速度,默认都是0
@property float greenSpeed;
@property float blueSpeed;
@property float alphaSpeed;
@property(nullable, strong) id contents; // 粒子的内容,设置为CGImageRef的对象
@property CGRect contentsRect;//粒子内容的位置
@property CGFloat contentsScale; //粒子内容的缩放比例
@property(copy) NSString *minificationFilter;//缩小的过滤器(基本不用)
@property(copy) NSString *magnificationFilter;//放大的过滤器(基本不用)
@property float minificationFilterBias;
@property(nullable, copy) NSArray<CAEmitterCell *> *emitterCells; // 粒子里面的粒子
@property(nullable, copy) NSDictionary *style;
复制代码

接下来重点说说CAEmitterCell一些常用的属性:

1.CAEmitterCell决定粒子生命周期的属性

  • lifetime、lifetimeRange:粒子在系统上的生命周期,即存活时间,单位是秒。配合lifetimeRage来让粒子生命周期均匀变化,以便可以让粒子的出现和消失显得更加离散。
  • birthRate:粒子产生数量的决定参数,它表示CAEmitterLayer上每秒产生的粒子数量,是浮点数。对于这个数量为浮点数,在测试的时候可以灵活使用它。比如你想看粒子的运动状态,但是太多了可能会很迷糊,这时候你把birthRate 设置成0.1f,把lifetime设置时间较长,就能看到单个粒子的运动状态。

2.CAEmitterCell决定粒子内容的属性

  • contents:为CGImageRef的对象。关于contents会联想到CALayer了,在CALayer中展示静态的图片是需要用到这个属性。在CAEmitterCell上它的意义也是一样的。但是因为粒子系统可以给粒子上色,为了做出好的颜色变换效果,通常提供的图片为白色的纯色的图片,

  • name:粒子的名字,当CAEmitterLayer里面有很多个cell的时候,可以给每个cell设置好名字,要修改一些属性以达到动画效果的改变等,就可以通过KVC拿到这个cell的某个属性。

3.CAEmitterCell决定粒子颜色状态的属性

  • color:color是粒子的颜色属性,这个颜色属性的作用是给粒子上色,color 会结合contents内容的颜色来改变我们的CAEmitterCell,它的实现方法其实很简单,就是将contents自身的颜色的RGBA值 * color的RGBA值,就得到最终的粒子的颜色。我们想完全通过color来控制CAEmitterCell的颜色,那么最好就选用一张颜色值为(255,255,255),即白色的图片作为CAEmitterCell的contents。因为大家都知道在UIColor中,rgb值为255的component的值其实为1,因为白色的UIColor每个component都为1,CAEmitterCell的color中任意component乘以contents中颜色对应的component都会得到color上原来的值。
  • redRange、greenRange、blueRange、alphaRange:这些是对应的color的RGBA的取值范围,默认为0,取值范围为0~1,如果设置粒子的颜色为[[UIColor colorWithRed:0.3 green:0.5 blue:0.3 alpha:1.0]CGColor];再设置 redRange、greenRange、blueRange、alphaRange全部为0.1,那么也就是说在产生粒子时,粒子的颜色RGBA对应的取值范围是:R(0.1, 0.3),G(0.1, 0.5),B(0.1, 0.3),A(0.1, 1.0).
  • redSpeed、greenSpeed、blueSpeed、alphaSpeed:这些是对应的是粒子的RGBA的变化速度,默认为0,取值范围为0~1。表示每秒钟的RGBA的变化率,如果设置粒子颜色的RGBA,以及redSpeed,其他的属性没设置默认为0。粒子的生命周期(lifetime)为20秒,那么这个粒子从产生到消失的时间就是20秒。它的Red值为0,redSpeed为0.2,那么在粒子的这个生命周期内,粒子的每秒钟的Rde值就会增加0.2 * 255,表现在外观上的状态就是粒子颜色在不断变化,接近白色。最后粒子生命周期结束的时候,粒子的color正好是RGBA(1,1,1,1)。当然个变化的速度也可以负数,计算方式相同。

4.CAEmitterCell决定粒子运行轨迹的属性。

  • emissionLongitude:表示粒子飞行方向跟水平坐标轴(x轴)之间的夹角,默认是0,顺时针方向是正向。例如emissionLongtitude为0 ,则粒子顺着x轴飞行。如果想沿着Y轴向下飞行,那么可以设置emissionLongtitude = M_PI_2。

    iOS:CAEmitterLayer粒子效果
  • emissionLatitude:这个和emissionLongitude的原理是一样的,只不过是在三维平面上的x-z轴上与x轴的夹角。

  • emissionRange则决定了粒子的发射角度范围,同样是一个弧度值。表示粒子在沿着emissionLongtitude方向所形成的顶角为2倍emissionRange的扇形范围内发散。我们把emisstionLongtitude设置为M_PI_2,让粒子向下飞行,并且让emissionRange为M_PI_4,就会得到一个顶角为2 * PI/4的扇形区域,那么粒子就会在这个区域内发射

    iOS:CAEmitterLayer粒子效果
    iOS:CAEmitterLayer粒子效果
  • velocity、velocityRange、xAcceleration 、yAcceleration、zAcceleration:前面两个是粒子的初速度和初速度的范围,后面是三个分别是在x、y、z轴方向的加速度,当xAcceleration为正数时,粒子每秒向x轴正方向加速,为负数时则向负方向即水平向左加速。当yAcceleration为正数时,粒子向y轴的负方向加速,也是就是向下加速,否则向上加速。

  • spin,spinRange:是粒子的自转属性,表示每秒钟粒子自转的弧度数。粒子的自转是以弧度制来计算的,表示每秒钟粒子自转的弧度数。spin为正数代表粒子是顺时针旋转的,为负数的话就是逆时针旋转。如果粒子的生命周期就是10秒,那么你想让你的粒子这个生命周期内刚好自转1周,若spinRange为0,那么粒子的spin值就应该为((π/180)*360 )/10,就得到了每秒需要转动的弧度数。

5.CAEmitterCell子粒子的属性

emitterCells:CAEmitterCell的emitterCells跟CAEmitterLayer的一样,也是一个CAEmitterCell的数组。我们基本可以按照操作CAEmitterLayer的emitterCells一样来设置我们粒子的emitterCells。

不过在这里需要注意的是:

  1. CAEmitterCell是服从CAMediatiming协议的,我们通过控制子CAEmitterCell的beginTime来控制子CAEmitterCell的出现时机。当子CAEmitterCell的beginTime为0时,表示你的粒子从CAEmitterLayer上发射出来后就会立即开始发射子CAEmitterCell,而且子CAEmitterCell的beginTime是不能大于你的粒子的lifetime的。
  2. 无论粒子是从什么样的形状上发射出来的,当它要发射子CAEmitterCell的时候,子CAEmitterCell总是从kCAEmitterLayerPoint形状上由父粒子的中心发射出来的。
colorBallCell.birthRate = 20.f;
    colorBallCell.lifetime = 10.f;
    colorBallCell.velocity = 40.f;
    colorBallCell.velocityRange = 100.f;
    colorBallCell.yAcceleration = 15.f;
    colorBallCell.emissionLongitude = M_PI_2; 
    colorBallCell.emissionRange = M_PI_4l;
    colorBallCell.scale = 0.2;


    CAEmitterCell*subCell=[CAEmitterCell emitterCell];
    subCell.lifetime=5;
    subCell.birthRate=3;
    subCell.contents=(id)[UIImage imageNamed:@"circle_white"].CGImage;
    subCell.velocity=60;
    subCell.emissionLongitude= - M_PI_2;
    subCell.emissionRange=M_PI_4/4;
    subCell.beginTime=5;
    subCell.scale=0.5;
    colorBallCell.emitterCells=@[subCell];

    colorBallLayer.emitterCells = @[colorBallCell];
复制代码
iOS:CAEmitterLayer粒子效果

父粒子的发射方向是子粒子的emissionLongtitude为0时的飞行方向。

上述内容已将CAEmitterLayer和CAEmitterCell的属性基本介绍完毕,后续会再做补充,下面我们来看一个具体的案例,把这些属性全部串联起来。

案例

1.设置CAEmitterLayer

设置CAEmitterLayer以及它的一些模式,并添加到要显示的view的图层上,当然也可以替换view的图层。这里是直接添加到控制器的view的layer上的,这个view的layer是一个calyer类型的,如果想替换掉calyer,可以自定义view,并在view里面重写如下方法即可实现替换

// 替换view的layer
+ (Class)layerClass{return [CAEmitterLayer class];}
复制代码
#import "ViewController.h"

@interface ViewController ()
@property (nonatomic, strong) CAEmitterLayer * colorBallLayer;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.view.backgroundColor = [UIColor blackColor];
    [self setupEmitter];
    
}
- (void)setupEmitter{
    
    UILabel * label = [[UILabel alloc] initWithFrame:CGRectMake(0, 100, self.view.bounds.size.width, 50)];
    [self.view addSubview:label];
    label.textColor = [UIColor whiteColor];
    label.text = @"轻点或拖动来改变发射源位置";
    label.textAlignment = NSTextAlignmentCenter;
    
    // 1. 设置CAEmitterLayer
    CAEmitterLayer * colorBallLayer = [CAEmitterLayer layer];
    [self.view.layer addSublayer:colorBallLayer];
    self.colorBallLayer = colorBallLayer;
    
    //发射源的尺寸大小
    colorBallLayer.emitterSize = CGSizeMake(100, 10);
    //发射源的形状
    colorBallLayer.emitterShape = kCAEmitterLayerPoint;
    //发射模式
    colorBallLayer.emitterMode = kCAEmitterLayerPoints;
    //粒子发射形状的中心点
    colorBallLayer.emitterPosition = CGPointMake(self.view.layer.bounds.size.width/2, 20);
    
    // 2. 配置CAEmitterCell
    CAEmitterCell * colorBallCell = [CAEmitterCell emitterCell];
    //粒子名称
    colorBallCell.name = @"colorBallCell";
    //粒子产生率,默认为0
    colorBallCell.birthRate = 20.f;
    //粒子生命周期
    colorBallCell.lifetime = 10.f;
    //粒子速度,默认为0
    colorBallCell.velocity = 40.f;
    //粒子速度平均量
    colorBallCell.velocityRange = 100.f;
    //x,y,z方向上的加速度分量,三者默认都是0
    colorBallCell.yAcceleration = 15.f;
    //指定纬度,纬度角代表了在x-z轴平面坐标系中与x轴之间的夹角,默认0:
    colorBallCell.emissionLongitude = M_PI_2; // 向左
    //发射角度范围,默认0,以锥形分布开的发射角度。角度用弧度制。粒子均匀分布在这个锥形范围内;
    colorBallCell.emissionRange = M_PI_4; // 围绕X轴向左90度
    // 缩放比例, 默认是1
    colorBallCell.scale = 0.2;
    // 缩放比例范围,默认是0
    colorBallCell.scaleRange = 0.1;
    
    // 在生命周期内的缩放速度,默认是0
    colorBallCell.scaleSpeed = 0.02;
    // 粒子的内容,为CGImageRef的对象
    colorBallCell.contents = (id)[[UIImage imageNamed:@"circle_white"] CGImage];
    //颜色
    colorBallCell.color = [[UIColor colorWithRed:0.5 green:0.f blue:0.5 alpha:1.f] CGColor];
    // 粒子颜色red,green,blue,alpha能改变的范围,默认0
    colorBallCell.redRange = 1.f;
    colorBallCell.greenRange = 1.f;
    colorBallCell.alphaRange = 0.8;
    // 粒子颜色red,green,blue,alpha在生命周期内的改变速度,默认都是0
    colorBallCell.blueSpeed = 1.f;
    colorBallCell.alphaSpeed = -0.1f;
    
    
    
    CAEmitterCell*subCell=[CAEmitterCell emitterCell];
    subCell.lifetime=5;
    subCell.birthRate=3;
    subCell.contents=(id)[UIImage imageNamed:@"circle_white"].CGImage;
    subCell.velocity=60;
    subCell.emissionLongitude= - M_PI_2;
    subCell.emissionRange=M_PI_4/4;
    subCell.beginTime=5;
    subCell.scale=0.5;
    colorBallCell.emitterCells=@[subCell];
    // 添加
    colorBallLayer.emitterCells = @[colorBallCell];
}
复制代码

到此CAEmitterLayer和CAEmitterCell的属性配置都已完成,下面我们让发射源根据手指的点击位置进行改变:

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    CGPoint point = [self locationFromTouchEvent:event];
    [self setBallInPsition:point];
}

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    CGPoint point = [self locationFromTouchEvent:event];
    [self setBallInPsition:point];
}

/**
 * 获取手指所在点
 */
- (CGPoint)locationFromTouchEvent:(UIEvent *)event{
    UITouch * touch = [[event allTouches] anyObject];
    return [touch locationInView:self.view];
}
复制代码

下面我们用一个动画来实现移动发射源到手指点击的点上:

- (void)setBallInPsition:(CGPoint)position{
    
    //创建基础动画
    CABasicAnimation * anim = [CABasicAnimation animationWithKeyPath:@"emitterCells.colorBallCell.scale"];
    //fromValue
    anim.fromValue = @0.2f;
    //toValue
    anim.toValue = @0.5f;
    //duration
    anim.duration = 1.f;
    //线性起搏,使动画在其持续时间内均匀地发生
    anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    
    // 用事务包装隐式动画
    [CATransaction begin];
    //设置是否禁止由于该事务组内的属性更改而触发的操作。
    [CATransaction setDisableActions:YES];
    //为colorBallLayer 添加动画
    [self.colorBallLayer addAnimation:anim forKey:nil];
    //为colorBallLayer 指定位置添加动画效果
    [self.colorBallLayer setValue:[NSValue valueWithCGPoint:position] forKeyPath:@"emitterPosition"];
    //提交动画
    [CATransaction commit];
}
复制代码

下面我们来看下实现的效果:

iOS:CAEmitterLayer粒子效果

至此,一个简单的粒子效果的代码就写完成了,其实大部分内容都是在配置CAEmitterLayer与CAEmitterCell的属性,因为这两个类是苹果为开发者封装好的,可以直接使用,已经省去了大部分的时间,我们只需要调用属性即可。在以后的时间中,或许可以写一个OpenGL ES 的GLSL语言来实现粒子效果。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Web 2.0 Architectures

Web 2.0 Architectures

Duane Nickull、Dion Hinchcliffe、James Governor / O'Reilly / 2009 / USD 34.99

The "Web 2.0" phenomena has become more pervasive than ever before. It is impacting the very fabric of our society and presents opportunities for those with knowledge. The individuals who understand t......一起来看看 《Web 2.0 Architectures》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

SHA 加密
SHA 加密

SHA 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换