美文网首页
CAEmitterLayer

CAEmitterLayer

作者: 夜雨聲煩_ | 来源:发表于2017-07-17 17:29 被阅读0次

    http://www.jianshu.com/p/197c2257f597

    粒子动画

    CAEmitterLayer常用属性

    CAEmitterLayer并不是杂乱无章地发射粒子的,它发射粒子时的位置,发射的面积和面积对应的几何图形都是可以配置的,可以是一个点,或者一个方形、圆形等等

    emitterShape:发射形状

    是粒子从什么形状发射出来,它并不是表示粒子自己的形状

    • kCAEmitterLayerPoint :点
    • kCAEmitterLayerLine:线
    • kCAEmitterLayerRectangle :矩形
    • kCAEmitterLayerCircle:圆形
    • kCAEmitterLayerCuboid :正方体
    • kCAEmitterLayerSphere : 球

    后两个是3D效果粒子,避而不谈。

    emitterPosition:发射位置

    在粒子图层上粒子的发射点(支持隐式动画),决定了粒子发射形状的中心点。

    emitterSize:发射尺寸

    决定了粒子发射形状的大小。

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

    直线.png
    我们可以这样理解,emitterPosition是所选emitterShape的中心点,例如对于矩形是对角线交点,对于圆形是圆心,对于直线是中点。而emitterSize则决定了矩形的大小,圆形的大小,直线的长度。这样说应该就够通俗易懂了。
    emitterCell会以中心点抽象为一个点,在上述区域内出现。
    另外,我们可以将emitterCell的速度相关的属性全部设置为0,你也可以直接注释掉他们,采用默认值,这样我们将会得到一些不会移动的粒子,因为它们没有速度,这样我们能看清楚CAEmitterLayer的形状是什么
    kCAEmitterLayerPoint: ![Uploading emitterShape_line_037035.png . . .]

    kCAEmitterLayerLine:

    emitterShape_line.png

    kCAEmitterLayerRectangle:

    emitterShape_Rectangle.png

    kCAEmitterLayerCircle

    emitterShape_circle.png

    注意:
    emitterShape与emitterSize配合使用
    如果是kCAEmitterLayerPoint,emitterSize没有意义。如果是kCAEmitterLayerLine,emitterSize的高度没有意义。如果是其余两种,emitterSize宽高均有意义,如果此时不设置emitterSize,与kCAEmitterLayerPoint模式效果一样。

    emitterMode:发射模式

    emitterMode的作用是进一步决定发射的区域是在发射形状的哪一部份,当我们看到它的枚举时,也就能大概了解了。

    • kCAEmitterLayerPoints : 点发射
    • kCAEmitterLayerOutline : 线发射
    • kCAEmitterLayerSurface:面发射
    • kCAEmitterLayerVolume:容积发射,3D图形的体内

    当我们选择Points的时候,粒子会从发射形状的“顶点”发射出来,这里顶点只是一个简单的描述,有些图形不能用顶点来描述的,例如对于圆形来说,“顶点”就是圆心。Outline是指从形状的边界上发射,surface则是从形状的表面上发射,Voloume是相对于3D形状的“球体内”或“立方体内”发射,关于3D形状的问题,以后再说。
    注意:
    发射方式和emitterShape和emitterSize是配合使用的。当emitterShape和emitterSize共同描绘出点的时候,发射方式使用点发射,选线发射和面发射无意义,依然是点发射的效果。当emitterShape和emitterSize共同描绘出矩形时,发射方式选面发射,如果选点发射会从点发射,选线发射同理。
    emitterShape与emitterSize与emitterMode共同配合使用。同选点、线、或者面即可(其实功能有重叠部分,或可不用全部设置)

    renderModel:渲染模式,默认值是kCAEmitterLayerUnordered
    • kCAEmitterLayerUnordered:无序随机的
    • kCAEmitterLayerOldestFirst:最新的在上层出现
    • kCAEmitterLayerOldestLast:最新的在下层出现
    • kCAEmitterLayerBackToFront :由下层向上层涌动
    • kCAEmitterLayerAdditive :叠加显示

    渲染模式就是当新的Cell出现的时候,该图层是在上一个Cell的上面还是下面。Additive为叠加模式,叠加的位置颜色会变重。

    CAEmitterCell常用属性

    CAEmitterLayer决定了粒子系统的发射位置,致于怎么让粒子本身酷炫起来,就需要CAEmitterCell的帮助。

    (1)lifetime

    粒子在系统上单纯的存在时间,单位是秒,时间到了粒子即会消失。

    (2)lifetimeRange

    以lifetime为基准的时间跨度,单位是秒。即粒子存在的时间为lifetime为中心点,以lifetimeRange为跨度的随机数,它可以配合lifetime来让粒子生命周期均匀变化,以便可以让粒子的出现和消失显得更加离散。
    例如当lifetime=5,lifetimeRange=4时,实际的粒子存在时间为3-7秒。

    (3)birthRate

    粒子产生数量的决定参数,它表示CAEmitterLayer上每秒产生的粒子数量,birthRate是一个浮点数,即为0.1时表示每十秒产生一个粒子。

    (4)contents

    contents为cell的内容,类型为id,通常使用图片。用颜色创建图片的方法如下。

    -(UIImage*)imageWithColor:(UIColor*)color andSize:(CGSize)size
    {
        UIGraphicsBeginImageContext(size);
        CGContextRef context=UIGraphicsGetCurrentContext();
        CGContextSetFillColorWithColor(context, color.CGColor);
    
        CGRect rect=CGRectMake(0, 0, size.width, size.height);
        UIBezierPath*bezierPath=[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:size.width/2.0];
    
        CGContextAddPath(context, bezierPath.CGPath);
        CGContextFillPath(context);
        CGContextSetFillColorWithColor(context, color.CGColor);
        UIImage*theImage=UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return theImage;
    }
    

    同样contents也可以直接使用切图,代码如下:

    emitterCell.contents = (__bridge id _Nullable)[[UIImage imageNamed:@"imageName"] CGImage];
    

    使用bridge桥接NS类与CF类。
    注意:contents不能为空,不能使用图片名不存在的图片。且图片大小决定cell的初始大小。

    (5)color

    color作为cell的背景色,与contents配合使用。
    如果contents的颜色以[UIColor colorWithRed:1 green:1 blue:1 alpha:1]来创建,并且我们cell的color传入[UIColor colorWithRed:0.5 green:1 blue:1 alpha:1],那么最终颜色为[UIColor colorWithRed:0.5 green:1 blue:1 alpha:1]。
    同样如果使用蓝色的contents图片,黄色的color,最终会得到绿色图片。
    color和contents共同作用得出最终颜色。所以当使用contents图片控制cell时,color使用白色;当使用color控制cell时,contents使用纯白色图片(whiteColor,不可使用clearColor)。

    (6)redRange,greenRange,blueRange

    用于随机生成颜色,该属性为粒子生成时的颜色的容差范围,值为0~1。
    例如redRange为0.1,那么当你的粒子的color对应的rgb为(10,255,255)。那么在其它值取默认值的前提下,这个粒子在CAEmitterLayer上发射出来的时候,它的rgb中的red component会均匀分布在 10正负0.1*255之间,即[0,35],颜色值不能为负。

    (7)redSpeed,greenSpeed,blueSpeed

    用于颜色逐步变化,属性为粒子颜色的变化速度,它的取值范围也是0~1。表示每秒钟的颜色变化率,乘以粒子生命周期即为变化范围。
    例如你的粒子的颜色是rgb(0,255,255),并且你的粒子的redRange也为0 ,这表示你的粒子被发射出来的时候,它的颜色值中的红色值总是为0 。你的粒子的生命周期lifetime为10,即粒子可以存在10秒,10秒后会从layer上移除。那么当你的redSpeed取值为0.1时,你将会看到你的粒子的红色值每秒增加0.1*255,这个过程是连续不断变化,外观上看就是你的粒子越来越接近白色。当粒子到达生命结束的时候也就是10秒的时候,你的粒子的颜色也恰好变成了rgb(255,255,255)。

    (8)alphaRange和alphaSpeed

    同(6)、(7),控制透明度的初始范围和变化速率,可以通过此属性控制粒子的渐隐渐现。

    (9) emissionLongitude

    emissionLongtitude决定了粒子飞行方向跟水平坐标轴(x轴)之间的夹角,默认是0,即沿着x轴向右飞行。顺时针方向是正向,例如emissionLongtitude为0 ,则粒子顺着x轴飞行,如果你想让你的粒子发射出来后,沿着y轴向下飞行,那么emissionLongtitude就应该设置为PI/2。即90度,正如我所说的那样,顺时针方向是正方向。如果你想让你的粒子沿着y轴向上飞行,你可以将emissionLongtitude设置为 3*PI/2也可设置为 -PI/2。下图就简单展示了emissionLongtitude的几个典型取值,图中绿色箭头所指的方向就是当emissionLongtitude为箭头对应角度时的粒子飞行方向:

    方向对应数值.png
    (10)emissionRange

    emissionRange则决定了粒子的发散范围,同样是一个弧度值(radians),表示粒子在沿着emissionLongtitude方向所形成的顶角为2倍emissionRange的圆锥范围内发散。我们看例图:我们把emisstionLongtitude设置为-PI/2,让粒子向上飞行,并且让emissionRange为PI/4。那么按照上面的说法,我们应该能得到一个向上的,并且顶角为2 * PI/4的圆锥,结果应该如下图:

    emissionRange.png
    (11) emissionLatitude

    粒子Z轴上的发射角度,用于三维立体效果,可以不做设置。与emissionLongitude原理相同,默认为0,在平面上向下,为PI时向上。为PI/2是垂直屏幕向外,3*PI/2时垂直屏幕向里,在屏幕上表现为粒子不动。
    emissionLatitude的值为与平面的夹角,当存在值时,我们所看到的粒子运动距离实际上为该边长在平面上的垂直投影(直角边),小于velocity与lifeTime的乘积(斜边)。
    emissionRange的值可能也作用于emissionLatitude,这样所得出的粒子出没区域不再是单纯扇形(拥有更大的角度,更短的半径),更具有离散性。

    (12)velocity

    粒子的运动速度,配合lifeTime得出粒子活动区域。默认为0,即粒子不运动。
    velocity可以为负值,即沿反方向移动。

    (13)velocityRange

    粒子运动速度范围。例如当velocity为100,velocityRange为200时,最终速度范围为0~200。

    (14)xAcceleration yAcceleration zAcceleration

    这3个属性分别定义了3个坐标轴上的加速度,它们代表了不同坐标轴方向上的每秒的速度增量,与物理学上保持一致。即当加速度为正数时加速,为负数时减速,当速度减为负数时反向加速移动。

    (15)spin,spinRange

    粒子的自转。粒子的自转是以弧度制来计算的,表示每秒钟粒子自转的弧度数,2PI为每秒自转一周。例如你的粒子的生命周期就是10秒,那么你想让你的粒子在10秒内刚好自转1周,那么spin为2PI/10。另外,当spin为正数的时候,粒子是顺时针旋转的,为负数的话就是逆时针选转了。 spinRange就不多说了,跟其它range的意义和作用是一样的,让自转速度离散。

    (16)scale,scaleRange,scaleSpeed

    粒子的缩放。scale与scaleRange的值为0~1,可以更改粒子初始的大小。scaleSpeed表示粒子的变化速率,与以上其他属性含义相同。

    (17)subCell

    可以指定一个subcell作为cell的cells列表成员,完成粒子在完成动画消失时开始下一个动画。

    一个简单的下雨动画代码
    - (instancetype)initWithFrame:(CGRect)frame
    {
    
        self = [super initWithFrame:frame];
        if (self) {
            [self addSubview:self.backgroundImageView];
            self.backgroundColor = [UIColor clearColor];
            self.layer.masksToBounds = YES;
            dispatch_async(dispatch_get_main_queue(), ^{
              [self.layer addSublayer:self.emitter];
            });
        }
    
        return self;
    }
    
    - (UIImageView *)backgroundImageView
    {
        if (!_backgroundImageView) {
            _backgroundImageView = [[UIImageView alloc] initWithFrame:self.bounds];
            _backgroundImageView.image = [UIImage imageNamed:@"bg_rain"];
        }
        return _backgroundImageView;
    }
    
    - (CAEmitterLayer *)emitter
    {
        if (!_emitter) {
            _emitter = ({
    
                CAEmitterLayer *emitter = [CAEmitterLayer layer];
                emitter.backgroundColor = [UIColor clearColor].CGColor;
                emitter.emitterPosition = CGPointMake(self.bounds.size.width, -40);
                emitter.emitterSize = CGSizeMake(self.bounds.size.width * 1.5, 80);
                emitter.emitterMode = kCAEmitterLayerSurface;
                emitter.emitterShape = kCAEmitterLayerRectangle;
    
                CAEmitterCell *midEmitterCell = [self midEmitterCell];
                CAEmitterCell *smallEmitterCell = [self smallEmitterCell];
                CAEmitterCell *largeEmitterCell = [self largeEmitterCell];
    
                //add the cell to the emitter layer
                emitter.emitterCells = @[ midEmitterCell, smallEmitterCell, largeEmitterCell ];
                emitter;
            });
        }
    
        return _emitter;
    }
    
    - (CAEmitterCell *)largeEmitterCell
    {
        CAEmitterCell *emitterCell = [CAEmitterCell emitterCell];
    
        emitterCell.contents = (id)[[UIImage imageNamed:@"rain_large"] CGImage];
    
        emitterCell.name = @"rain_large";
    
        UIColor *color = [UIColor colorWithWhite:1.0 alpha:1.0];
        emitterCell.color = color.CGColor;
    
        emitterCell.birthRate = LargeRainrate;
        emitterCell.lifetime = lifeTime(2.1);
        emitterCell.lifetimeRange = 0;
        emitterCell.velocity = 150;
        emitterCell.velocityRange = 50;
    
        emitterCell.emissionLongitude = 2;
        emitterCell.emissionRange = 0;
    
    
        emitterCell.xAcceleration = -1;
        emitterCell.yAcceleration = 20;
        emitterCell.alphaRange = 0.8;
        emitterCell.alphaSpeed = 0.1;
    
        emitterCell.scale = 0.6;
        emitterCell.scaleRange = 0.2;
        emitterCell.scaleSpeed = 0.0;
    
    
        CAEmitterCell *subCell = [self waterCirleCell];
        emitterCell.emitterCells = @[ subCell ];
    
        return emitterCell;
    }
    
    - (CAEmitterCell *)midEmitterCell
    {
        CAEmitterCell *emitterCell = [CAEmitterCell emitterCell];
    
        emitterCell.contents = (id)[[UIImage imageNamed:@"rain_mid"] CGImage];
    
        emitterCell.name = @"rain_mid";
    
        UIColor *color = [UIColor colorWithWhite:1.0 alpha:1.0];
        emitterCell.color = color.CGColor;
    
        emitterCell.birthRate = MidRainrate;
        emitterCell.lifetime = lifeTime(2.0);
        emitterCell.lifetimeRange = 0;
        emitterCell.velocity = 150;
        emitterCell.velocityRange = 50;
    
        emitterCell.emissionLongitude = 2;
        emitterCell.emissionRange = 0;
    
    
        emitterCell.xAcceleration = -1;
        emitterCell.yAcceleration = 25;
        emitterCell.alphaRange = 0.8;
        emitterCell.alphaSpeed = -0.1;
    
        emitterCell.scale = 0.6;
        emitterCell.scaleRange = 0.2;
        emitterCell.scaleSpeed = 0.0;
    
        return emitterCell;
    }
    
    - (CAEmitterCell *)smallEmitterCell
    {
        CAEmitterCell *emitterCell = [CAEmitterCell emitterCell];
    
        emitterCell.contents = (id)[[UIImage imageNamed:@"rain_small"] CGImage];
    
        emitterCell.name = @"rain_small";
    
        UIColor *color = [UIColor colorWithWhite:1.0 alpha:1.0];
        emitterCell.color = color.CGColor;
    
        emitterCell.birthRate = SmallRainrate;
        emitterCell.lifetime = lifeTime(2.0);
        emitterCell.lifetimeRange = 0;
        emitterCell.velocity = 200;
        emitterCell.velocityRange = 50;
    
        emitterCell.emissionLongitude = 2;
        emitterCell.emissionRange = 0;
    
    
        emitterCell.xAcceleration = -1;
        emitterCell.yAcceleration = 30;
        emitterCell.alphaRange = 0.6;
        emitterCell.alphaSpeed = -0.2;
    
        emitterCell.scale = 0.6;
        emitterCell.scaleRange = 0.2;
        emitterCell.scaleSpeed = 0.0;
    
        return emitterCell;
    }
    
    
    - (CAEmitterCell *)waterCirleCell
    {
        //create new emitter cell
        CAEmitterCell *emitterCell = [CAEmitterCell emitterCell];
        emitterCell.beginTime = lifeTime(2.05);
        //粒子图片
        emitterCell.contents = (__bridge id _Nullable)[[UIImage imageNamed:@"circle_small"] CGImage];
        //粒子源名称
        emitterCell.name = @"circle_small";
        //get the particles start color
        UIColor *color = [UIColor whiteColor];
        emitterCell.color = color.CGColor;
        //copy all the settings to the emitter cell
        //产生速率
        emitterCell.birthRate = 1;
    
        //生命周期
        emitterCell.lifetime = 2.4;
    
        //透明度
        emitterCell.alphaRange = 0.8;
        //透明度变化速度
        emitterCell.alphaSpeed = -0.3;
    
        //缩放
        emitterCell.scale = 0.4;
        emitterCell.scaleRange = 0.3;
        emitterCell.scaleSpeed = 0.4;
    
    
        return emitterCell;
    }
    
    

    相关文章

      网友评论

          本文标题:CAEmitterLayer

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