美文网首页IOS个人开发将来跳槽用iOS
iOS中粒子发射(封装下雨,下雪,喷火等特效)

iOS中粒子发射(封装下雨,下雪,喷火等特效)

作者: 哈哈大p孩 | 来源:发表于2016-06-29 15:04 被阅读3242次

    在iOS中实现粒子特效,有对应的的属性CAEmitterLayer,它是Layer的子类,用它来实现粒子特效不会怎么占用资源,从而去影响UI的流程性。
    粒子CAEmitterLayer发射器的基本属性

    //是否允许在规定的范围内
    @property BOOL masksToBounds;
    
    //发射器的形状
    //kCAEmitterLayerPoint 点的形状,粒子从一个点发出
    //kCAEmitterLayerLine 线的形状,粒子从一条线发出
    //kCAEmitterLayerRectangle 矩形形状,粒子从一个矩形中发出
    //kCAEmitterLayerCuboid 立方体形状,会影响z平面的效果
    //kCAEmitterLayerCircle 圆形,粒子会在圆形范围发射
    //kCAEmitterLayerSphere 球形
    @property(copy) NSString *emitterShape;
    
    //发射器的发射模式
    //kCAEmitterLayerPoints 从发射器中发出
    //kCAEmitterLayerOutline 从发射器边缘发出
    //kCAEmitterLayerSurface 从发射器表面发出
    //kCAEmitterLayerVolumen 从发射器中点发出
    @property(copy) NSString *emitterMode;
    
    // 发射器的尺寸大小
    @property CGSize emitterSize;
    
    //发射器在xy平面的中心位置
    @property CGPoint emitterPosition;
    
    //发射器在Z平面的位置
    @property CGFloat emitterZPosition;
    

    粒子的属性,也就是特效,需要用到CAEmitterCell这个类

    //类方法创建发射单元
    + (instancetype)emitterCell;
    
    //粒子的创建速率
    @property float birthRate;
    
    //粒子的生存时间
    @property float lifetime;
    
    //粒子的生存时间容差
    @property float lifetimeRange;
    
    //粒子在Z轴方向的发射角度
    @property CGFloat emissionLatitude;
    
    //粒子在xy平面的发射角度
    @property CGFloat emissionLongitude;
    
    //粒子发射角度的容差
    @property CGFloat emissionRange;
    
    //粒子的速度
    @property CGFloat velocity;
    
    //粒子速度的容差
    @property CGFloat velocityRange;
    
    //x,y,z三个方向的加速度
    @property CGFloat xAcceleration;
    @property CGFloat yAcceleration;
    @property CGFloat zAcceleration;
    
    //缩放大小,缩放容差和缩放速度
    @property CGFloat scale;
    @property CGFloat scaleRange;
    @property CGFloat scaleSpeed;
    
    //旋转度与旋转容差
    @property CGFloat spin;
    @property CGFloat spinRange;
    
    //
    @property CGColorRef color;
    
    //粒子在rgb三个色相上的容差和透明度的容差
    @property float redRange;
    @property float greenRange;
    @property float blueRange;
    @property float alphaRange;
    
    //粒子在RGB三个色相上的变化速度和透明度的变化速度
    @property float redSpeed;
    @property float greenSpeed;
    @property float blueSpeed;
    @property float alphaSpeed;
    
    //渲染粒子,可以设置为一个CGImage的对象
    @property(strong) id contents;
    
    //渲染的范围
    @property CGRect contentsRect;
    
    

    好,接下来我们看一下他的基本用法。

        //创建出layer
        CAEmitterLayer *emitterLayer = [CAEmitterLayer layer];//遍历构造器创建
        //给定尺寸
        emitterLayer.frame = CGRectMake(100, 100, 100, 100);
        //显示边框
        emitterLayer.borderWidth = 1.f;
        //发射点
        emitterLayer.emitterPosition = CGPointMake(0, 0);
        
    //    emitterLayer.masksToBounds = YES;
        
        //发射模式
        emitterLayer.emitterMode = kCAEmitterLayerSurface;
        //发射形状
        emitterLayer.emitterShape = kCAEmitterLayerLine;
        
        [self.view.layer addSublayer:emitterLayer];
        
        CAEmitterCell *cell = [CAEmitterCell emitterCell];
        //粒子产生率
        cell.birthRate = 1.f;
        //粒子生命周期
        cell.lifetime = 120.f;
        //速度值
        cell.velocity = 10;
        //速度值的微调值
        cell.velocityRange = 3.f;
        //y轴加速度
        cell.yAcceleration = 2.f;
        //发射角度
        cell.emissionRange = 0.5 *M_1_PI;
        //设置粒子颜色
    //    cell.color = [UIColor blueColor].CGColor;
        
        cell.contents = (__bridge id _Nullable)([UIImage imageNamed:@"234"].CGImage);
        //让CAEmitterCell与CAEmitterLayer产生关系
        emitterLayer.emitterCells = @[cell];
    

    然后运行后得到的效果如下:

    caotu.gif

    CAEmitterLayer基本的使用也就这样,但为了避免繁琐的设置,我们将CAEmitterLayer封装成一个较为通用的父类供子类使用。

    首先创建一个继承UIView的视图CAEmitterLayerView,由于此view默认创建的隐式layer不是CAEmitterLayer,所以我们需要在CAEmitterLayerView.m中重写layerClass方法,返回CAEmitterLayer。由于CAEmitterLayer含有非常多的属性要设置,如果都写在CAEmitterLayerView.h中的话,会显得非常的繁琐,所以在这里我们写set和get方法,通过这个方法,当我们需要使用哪个属性的时候,再在子类中进行调用即可。CAEmitterLayerView的代码如下:
    CAEmitterLayerView.h

    @interface CAEmitterLayerView : UIView
    //模仿setter,getter方法
    - (void)setEmitterLayer:(CAEmitterLayer *)layer;
    - (CAEmitterLayer *)emitterLayer;
    
    //显示出当前view
    - (void)show;
    //隐藏
    - (void)hide;
    @end
    

    CAEmitterLayerView.m

    @interface CAEmitterLayerView() {
        CAEmitterLayer *_emitterLayer;
    }
    
    @end
    
    @implementation CAEmitterLayerView
    +(Class)layerClass {
        return [CAEmitterLayer class];
    }
    
    - (instancetype)initWithFrame:(CGRect)frame {
        self = [super initWithFrame:frame];
        if (self) {
            _emitterLayer = (CAEmitterLayer *)self.layer;
        }
        return self;
    }
    
    - (void)setEmitterLayer:(CAEmitterLayer *)layer {
        _emitterLayer = layer;
    }
    
    - (CAEmitterLayer *)emitterLayer {
        return _emitterLayer;
    }
    
    - (void)show {
    
    }
    
    - (void)hide {
    
    }
    

    好了,通过这种方法,我们在项目中倘若要设计下雨或者下雪等效果时候,只需要继承该CAEmitterLayerView,然后在子类中实现对应的效果即可。

    1.下雪效果
    首先创建一个CAEmitterLayerView的子类视图SnowView,在.m中的代码如下

    - (instancetype)initWithFrame:(CGRect)frame {
        self = [super initWithFrame:frame];
        if (self) {
            [self setup];
        }
        return self;
    }
    
    - (void)setup {
     //初始化一些参数
        self.emitterLayer.masksToBounds = YES;
        self.emitterLayer.emitterShape = kCAEmitterLayerLine;
        self.emitterLayer.emitterMode = kCAEmitterLayerSurface;
        self.emitterLayer.emitterSize = self.frame.size;
        self.emitterLayer.emitterPosition = CGPointMake(self.bounds.size.width / 2.f, -20);
    }
    
    - (void)show {
       //配置
        CAEmitterCell *snowFlake = [CAEmitterCell emitterCell];
        snowFlake.birthRate = 1.f;
        snowFlake.speed = 10.f;
        snowFlake.velocity = 2.f;
        snowFlake.velocityRange = 10.f;
        snowFlake.yAcceleration = 10.f;
        snowFlake.emissionRange = 0.5 * M_PI;
        snowFlake.spinRange = 0.25 * M_PI;
        snowFlake.contents = (__bridge id _Nullable)([UIImage imageNamed:@"234"].CGImage);
        snowFlake.color = [UIColor redColor].CGColor;
        snowFlake.lifetime = 180.f;
        snowFlake.scale = 0.5;
        snowFlake.scaleRange = 0.3;
        
        //添加动画
        self.emitterLayer.emitterCells = @[snowFlake];
    }
    

    下雪模型已搭建好,然后在我们的控制器中导入SnowView

        SnowView *sView = [[SnowView alloc] initWithFrame:CGRectMake(100, 400, 100, 100)];
        [self.view addSubview:sView];
        [sView show];
    

    效果如下:

    snow.gif

    2.下雨效果
    创建一个CAEmitterLayerView的子类视图RainView,在.m中的代码如下

    - (instancetype)initWithFrame:(CGRect)frame {
        self = [super initWithFrame:frame];
        if (self) {
            [self setup];
        }
        return self;
    }
    
    - (void)setup {
        self.emitterLayer.masksToBounds = YES;
        self.emitterLayer.emitterShape = kCAEmitterLayerLine;
        self.emitterLayer.emitterMode = kCAEmitterLayerSurface;
        self.emitterLayer.emitterSize = self.frame.size;
        self.emitterLayer.emitterPosition
        = CGPointMake(self.bounds.size.width / 2.f, -20);
    }
    
    - (void)show {
        CAEmitterCell *rainFlake = [CAEmitterCell emitterCell];
        rainFlake.birthRate = 25.f;
        rainFlake.speed = 10.f;
        rainFlake.velocity = 10.f;
        rainFlake.velocityRange = 10.f;
        rainFlake.yAcceleration = 1000.f;
        rainFlake.contents = (__bridge id _Nullable)([UIImage imageNamed:@"234"].CGImage);
        rainFlake.color = [UIColor blackColor].CGColor;
        rainFlake.lifetime = 7.f;
        rainFlake.scaleRange = 0.f;
        rainFlake.scale = 0.2f;
        //添加动画
        self.emitterLayer.emitterCells = @[rainFlake];
    }
    

    效果如下(图片可以切长点,我在这里没改图片,看着效果并没那么好):

    rain.gif

    3.火焰
    创建一个CAEmitterLayerView的子类视图fireView,在这里设置了两个CAEmitterCell(特效),在.m中的代码如下

    - (instancetype)initWithFrame:(CGRect)frame {
        self = [super initWithFrame:frame];
        if (self) {
            [self setup];
        }
        return self;
    }
    
    - (void)setup {
        self.emitterLayer.masksToBounds = YES;
        self.emitterLayer.renderMode = kCAEmitterLayerAdditive;
        self.emitterLayer.emitterSize = CGSizeMake(self.bounds.size.width - 100, 20);
        self.emitterLayer.emitterPosition
        = CGPointMake(self.bounds.size.width / 2.f, self.bounds.size.height - 20);
    }
    
    - (void)show {
        //火焰
      CAEmitterCell * fire = [CAEmitterCell emitterCell];
        fire.birthRate=800;
        fire.lifetime=2.0;
        fire.lifetimeRange=1.5;
        fire.color=[[UIColor colorWithRed:0.8 green:0.4 blue:0.2 alpha:0.1]CGColor];
        fire.contents=(id)[[UIImage imageNamed:@"fire"]CGImage];
        
        fire.velocity=160;
        fire.velocityRange=80;
        fire.emissionLongitude=M_PI+M_PI_2;
        fire.emissionRange=M_PI_2;
        
        
        
        fire.scaleSpeed=0.3;
        fire.spin=0.2;
        
        //烟雾
        CAEmitterCell * smoke = [CAEmitterCell emitterCell];
        smoke.birthRate=400;
        smoke.lifetime=3.0;
        smoke.lifetimeRange=1.5;
        smoke.color=[[UIColor colorWithRed:1 green:1 blue:1 alpha:0.05]CGColor];
        smoke.contents=(id)[[UIImage imageNamed:@"smoke"]CGImage];
        
        smoke.velocity=250;
        smoke.velocityRange=100;
        smoke.emissionLongitude=M_PI+M_PI_2;
        smoke.emissionRange=M_PI_2;
        
        self.emitterLayer.emitterCells = [NSArray arrayWithObjects:smoke,fire, nil];
    }
    

    效果如下:

    fire.gif

    相关文章

      网友评论

      本文标题:iOS中粒子发射(封装下雨,下雪,喷火等特效)

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