美文网首页
CAEmitterLayer(粒子效果)

CAEmitterLayer(粒子效果)

作者: 莪的世界木有如果 | 来源:发表于2018-08-22 17:03 被阅读25次

    CAEmitterLayer看上去像是许多CAEmitterCell的容器,这些CAEmitierCell定义了一个例子效果。你将会为不同的例子效果定义一个或多个CAEmitterCell作为模版,同时CAEmitterLayer负责基于这些模版实例化一个粒子流。一个CAEmitterCell类似于一个CALayer:它有一个contents属性可以定义为一个CGImage,另外还有一些可设置属性控制着表现和行为。我们不会对这些属性逐一进行详细的描述,你们可以在CAEmitterCell类的头文件中找到。

    GitHub项目地址CAAnimation_CAEmitterLayer工程里面的viewController

    下面是对CAEmitterLayer和CAEmitterCell的一些属性说明:

    1、CAEmitterLayer

    //装着CAEmitterCell对象的数组,被用于把粒子投放到layer上
    @property(nullable, copy) NSArray<CAEmitterCell *> *emitterCells;
    //粒子产生系数,默认1.0
    @property float birthRate;
    //粒子生命周期
    @property float lifetime;
    //发射位置
    @property CGPoint emitterPosition;
    //发射源的z坐标位置
    @property CGFloat emitterZPosition;
    //发射源的大小
    @property CGSize emitterSize;
    //决定粒子形状的深度联系:emitter shape
    @property CGFloat emitterDepth;
    
    //发射源的形状
    @property(copy) NSString *emitterShape;
    - 取值
    NSString * const kCAEmitterLayerPoint;
    NSString * const kCAEmitterLayerLine;
    NSString * const kCAEmitterLayerRectangle;
    NSString * const kCAEmitterLayerCuboid;
    NSString * const kCAEmitterLayerCircle;
    NSString * const kCAEmitterLayerSphere;
    
    //发射模式
    @property(copy) NSString *emitterMode;
    - 取值
    NSString * const kCAEmitterLayerPoints;
    NSString * const kCAEmitterLayerOutline;
    NSString * const kCAEmitterLayerSurface;
    NSString * const kCAEmitterLayerVolume;
    
    //渲染模式
    @property(copy) NSString *renderMode;
    - 取值
    NSString * const kCAEmitterLayerUnordered;
    NSString * const kCAEmitterLayerOldestFirst;
    NSString * const kCAEmitterLayerOldestLast;
    NSString * const kCAEmitterLayerBackToFront;
    NSString * const kCAEmitterLayerAdditive;
    
    //粒子是否平展在层上
    @property BOOL preservesDepth;
    //粒子速度
    @property float velocity;
    //粒子的缩放比例
    @property float scale;
    //自旋转速度
    @property float spin;
    //用于初始化随机数产生的种子
    @property unsigned int seed;
    

    2、CAEmitterCell的属性

    //初始化方法
    + (instancetype)emitterCell;
    //根据健 获 得 值
    + (nullable id)defaultValueForKey:(NSString *)key;
    //是否 归 档莫 键值
    - (BOOL)shouldArchiveValueForKey:(NSString *)key;
    //粒子的名字
    @property(nullable, copy) NSString *name;
    //粒子是否被渲染
    @property(getter=isEnabled) BOOL enabled;
    //粒子参数的速度乘数因子
    @property float birthRate;
    //生命周期
    @property float lifetime;
    //生命周期范围
    @property float lifetimeRange;
    //发射的 z 轴方向的角度 
    @property CGFloat emissionLatitude;
    //x-y 平面的 发 射方向
    @property CGFloat emissionLongitude;
    //周 围发射角度
    @property CGFloat emissionRange;
    //速度
    @property CGFloat velocity;
    //速度范围
    @property CGFloat velocityRange;
    //粒子 x 方向的加速度分量
    @property CGFloat xAcceleration;
    //粒子 y 方向的加速度分量
    @property CGFloat yAcceleration;
    //粒子 z 方向的加速度分量
    @property CGFloat zAcceleration;
    //缩放比例
    @property CGFloat scale;
    //缩放比例范围
    @property CGFloat scaleRange;
    //缩放比例速度
    @property CGFloat scaleSpeed;
    //子旋转角度
    @property CGFloat spin;
    //子旋转角度范围
    @property CGFloat spinRange;
    //粒子的颜色
    @property(nullable) CGColorRef color;
    //一个粒子的 颜 色 red   能改 变 的范 围
    @property float redRange;
    //一个粒子的 颜 色 green   能改 变 的范 围
    @property float greenRange;
    //一个粒子的 颜 色 blue   能改 变 的范 围
    @property float blueRange;
    //一个粒子的 颜 色 alpha 能改 变 的范 围
    @property float alphaRange;
    //粒子 red 在生命周期内的改变速度
    @property float redSpeed;
    //粒子 green 在生命周期内的改变速度
    @property float greenSpeed;
    //粒子 blue 在生命周期内的改变速度
    @property float blueSpeed;
    //粒子透明度在生命周期内的改变速度
    @property float alphaSpeed;
    //是个 CGImageRef 的对象 , 既粒子要展现的图片
    @property(nullable, strong) id contents;
    //应该画在 contents 里的子 rectangle
    @property CGRect contentsRect;
    //定义了寄宿图的像素尺寸和视图大小的比例,默认情况下它是一个值为1.0的浮点数
    @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;
    

    1、下雨效果

    rain.gif

    实现代码:

    /**
         * 心形雨
         */
        private func setUpRainEmitterLayer(){
            rainEmitterLayer = CAEmitterLayer()
            //渲染模式
            rainEmitterLayer.renderMode = kCAEmitterLayerOldestFirst;
            //发射模式,为线性边缘
            rainEmitterLayer.emitterMode = kCAEmitterLayerOutline;
            //发射源的形状,线性的(就是一条线上都可以发射粒子)
            rainEmitterLayer.emitterShape = kCAEmitterLayerLine;
            //设置发射源的位置
            rainEmitterLayer.emitterPosition = CGPoint(x: view.bounds.midX, y: 0)
            //设置发射源的范围
            rainEmitterLayer.emitterSize = CGSize(width: view.bounds.width, height: 0)
            //设置动画默认停止
            rainEmitterLayer.birthRate = 0
            
            //初始化CAEmitterCell
            let cell = CAEmitterCell()
            //设置cell的内容
            cell.contents = #imageLiteral(resourceName: "Heart_red").cgImage
            //设置scale的系数
            cell.scale = 0.1
            //设置周期时间(每个粒子在屏幕中持续的时间)
            cell.lifetime = 5
            //设置粒子数
            cell.birthRate = 1000
            //设置粒子加速度
            cell.velocity = 500
            //设置发射方向(x-y屏面)
            cell.emissionLongitude = CGFloat.pi
            //设置粒子cell
            rainEmitterLayer.emitterCells = [cell]
            
            self.view.layer.addSublayer(rainEmitterLayer)
        }
    

    rain按钮点击事件:

    @IBAction func rainButtonClick(_ sender: UIButton) {
            sender.isUserInteractionEnabled = false
            //设置动画
            let rainAnimation = CABasicAnimation(keyPath: "birthRate")
            rainAnimation.duration = 3.0
            if rainEmitterLayer.birthRate == 0 {
                rainAnimation.fromValue = 0
                rainAnimation.toValue = 1
                rainEmitterLayer.birthRate = 1
            }else{
                rainAnimation.fromValue = 1
                rainAnimation.toValue = 0
                rainEmitterLayer.birthRate = 0
            }
            rainEmitterLayer.add(rainAnimation, forKey: "birthRate")
            DispatchQueue.main.asyncAfter(deadline: .now() + rainAnimation.duration) {
                [weak self] in
                /*
                 guard语句和if语句有点类似,都是根据其关键字之后的表达式的布尔值决定下一步执行什么。但与if语句不同的是,guard语句只会有一个代码块,不像if语句可以if else多个代码块。
                 
                 那么guard语句的作用到底是什么呢?顾名思义,就是守护。guard语句判断其后的表达式布尔值为false时,才会执行之后代码块里的代码,如果为true,则跳过整个guard语句
                 */
                guard self != nil else{return}
                sender.isUserInteractionEnabled = true
            }
            
        }
    

    2、上升心形动画

    上升心形动画.gif

    代码实现:

    /**
         * 曲线上升心形动画效果
         */
        private func setUpRightHeartLayer(){
            //设置rightHeartLayer
            rightHeartLayer = CAEmitterLayer()
            //设置发射源的形状
            rightHeartLayer.emitterMode = kCAEmitterLayerPoint
            //设置发射源的发射模式
    //        rightHeartLayer.emitterShape = kCAEmitterLayerVolume
            //设置渲染模式
            rightHeartLayer.renderMode = kCAEmitterLayerOldestFirst
            //设置发射源的位置
            rightHeartLayer.emitterPosition = rightHeartButton.center
            //设置birthRate
            rightHeartLayer.birthRate = 0
            
            //初始化CAEmitterLayer
            let cell = CAEmitterCell()
            //设置cell的contents
            cell.contents = #imageLiteral(resourceName: "Heart_red").cgImage
            //设置粒子数
            cell.birthRate = 5
            //设置周期时间
            cell.lifetime = 1
            //设置cell的scale系数
            cell.scale = 0.5
            //设置scale的speed系数
    //        cell.scaleSpeed = -0.1
            //设置alpha的speed系数
            cell.alphaSpeed = -1
            //设置粒子速度
            cell.velocity = 50
            //设置粒子发射角度
            cell.emissionLongitude = -CGFloat.pi/2
            cell.emissionRange = CGFloat.pi/4
            
            rightHeartLayer.emitterCells = [cell]
            self.view.layer.addSublayer(rightHeartLayer)
        }
    

    右侧心形按钮的点击方法

    @IBAction func rightHeartButtonClick(_ sender: UIButton) {
            sender.isUserInteractionEnabled = false
            //设置时间参数
            rightHeartLayer.beginTime = CACurrentMediaTime()
            /*所有的cells是在一定时间里面生成的,并不是同一时刻生成的,所以如果设置的延迟时间过少的话,cells有可能没有或者只有一两个,这里要注意*/
            rightHeartLayer.birthRate = 1
            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {[weak self] in
                guard let strongSelf = self else {return}
                strongSelf.rightHeartLayer.birthRate = 0
            }
            
            DispatchQueue.main.asyncAfter(deadline: .now() + 1.6) {[weak self] in
                guard self != nil else {return}
                sender.isUserInteractionEnabled = true
            }
        }
    

    3、粒子放射效果

    粒子放射效果.gif

    代码实现:

    /**
         * 粒子放射效果
         */
        private func setUpCenterHeartLayer(){
            //设置centerHeartLayer
            centerHeartLayer = CAEmitterLayer()
            //设置发射源粒的形状
            centerHeartLayer.emitterShape = kCAEmitterLayerCircle
            //设置发射粒子的模式
            centerHeartLayer.emitterMode = kCAEmitterLayerOutline
            //设置渲染效果
            centerHeartLayer.renderMode = kCAEmitterLayerOldestFirst
            //设置发射源的位置
            centerHeartLayer.emitterPosition = centerHeartButton.center
            //设置发射源的大小
            centerHeartLayer.emitterSize = centerHeartButton.bounds.size
            centerHeartLayer.birthRate = 0
            
            //设置CAEmitterCell
            let cell = CAEmitterCell()
            //设置cell的内容
            cell.contents = #imageLiteral(resourceName: "Heart_red").cgImage
            //设置周期时间
            cell.lifetime = 1
            //设置scale大小
            cell.scale = 0.05
            //设置粒子数
            cell.birthRate = 2000
            //设置scale的speed
            cell.scaleSpeed = -0.02
            //设置alpha的speed
            cell.alphaSpeed = -1
            //设置粒子的速度
            cell.velocity = 30
            
            centerHeartLayer.emitterCells = [cell]
            self.view.layer.addSublayer(centerHeartLayer)
            
        }
    

    中间心形按钮点击事件:

     @IBAction func centerHeartButtonClick(_ sender: UIButton) {
            sender.isUserInteractionEnabled = false
            //设置时间参数
            centerHeartLayer.beginTime = CACurrentMediaTime()//在0.2秒后设置birthrate=0,这个0.2秒的时间内,cell只生成一部分,并没有2000个全部完成。
            centerHeartLayer.birthRate = 1
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {[weak self] in
                guard let strongSelf = self else {return}
               strongSelf.centerHeartLayer.birthRate = 0
            }
            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {[weak self] in
                guard self != nil else {return}
                sender.isUserInteractionEnabled = true
            }
        }
    

    4、烟花效果

    烟花效果.gif

    代码实现:

    private func setUpGratilyEmitterLayer(layer:CAEmitterLayer!,point:CGPoint!,angle:CGFloat!,angleRange:CGFloat!){
            //设置发射源的形状
            layer.emitterMode = kCAEmitterLayerPoint
            //设置发射源的发射模式
            layer.emitterMode = kCAEmitterLayerVolume
            //设置渲染模式
            layer.renderMode = kCAEmitterLayerOldestFirst
            //设置发射源的位置
            layer.emitterPosition = point
            //设置birthRate
            layer.birthRate = 0
            
            //初始化红❤️EmitterCell
            let redCell = CAEmitterCell()
            //设置cell的contents
            redCell.contents = #imageLiteral(resourceName: "Heart_red").cgImage
            //设置cell的scale
            redCell.scale = 0.5
            //设置alpha
            redCell.alphaSpeed = -0.1
            //设置周期时间
            redCell.lifetime = 20
            //设置粒子速度
            redCell.velocity = 100
            //设置粒子个数
            redCell.birthRate = 10
            //设置Y轴方向的分支速度
            redCell.yAcceleration = 20
            //设置发射角度
            redCell.emissionLongitude = angle
            /*设置发射角度的浮动值(这个浮动值是基于emissionLongitude的角度位置的,比如
    emissionLongitude是CGFloat.pi/4,emissionRange为CGFloat.pi/4,则发射点发射
    角度浮动范围就在CGFloat.pi/4-CGFloat.pi/8到 CGFloat.pi/4 + CGFloat.pi/8)*/
            redCell.emissionRange = angleRange
            //粒子自旋角度
            redCell.spin = 0
            //粒子自旋角度浮动值
            redCell.spinRange = CGFloat.pi * 2
            
            //初始化蓝❤️EmitterCell
            let blueCell = CAEmitterCell()
            //设置cell的contents
            blueCell.contents = #imageLiteral(resourceName: "Heart_blue").cgImage
            //设置scale
            blueCell.scale = 0.5
            //设置周期时间
            blueCell.lifetime = 20
            //设置粒子数
            blueCell.birthRate = 5
            //设置粒子速度
            blueCell.velocity = 130
            //设置alpha
            blueCell.alphaSpeed = -0.1
            //设置Y轴的分支速度
            blueCell.yAcceleration = 20
            //设置发射角度
            blueCell.emissionLongitude = angle
            //设置发射角度浮动值
            blueCell.emissionRange = angleRange
            //设置自旋角度
            blueCell.spin = 0
            //设置自旋角度浮动值
            blueCell.spinRange = CGFloat.pi * 2
            
            layer.emitterCells = [redCell,blueCell]
            
            view.layer.addSublayer(layer)
        }
    

    gravity按钮点击事件:

    @IBAction func gravityButtonClick(_ sender: UIButton) {
            sender.isUserInteractionEnabled = false
            leftGravityLayer.beginTime = CACurrentMediaTime()
            rightGravityLayer.beginTime = CACurrentMediaTime()
            leftGravityLayer.birthRate = 1
            rightGravityLayer.birthRate = 1
            DispatchQueue.main.asyncAfter(deadline: .now() + 10) {[weak self] in
                guard let strongSelf = self else {return}
                strongSelf.leftGravityLayer.birthRate = 0
                strongSelf.rightGravityLayer.birthRate = 0
            }
            DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) {[weak self] in
                guard self != nil else {return}
                sender.isUserInteractionEnabled = true
            }
        }  
    }
    

    一些自己研究过程中遇到比较难解的问题在代码中已经注释了。

    相关文章

      网友评论

          本文标题:CAEmitterLayer(粒子效果)

          本文链接:https://www.haomeiwen.com/subject/eifjiftx.html