How do you remove the CAEmitterLayer when it expires. CAEmitter Cells - instead of repeating until you remove it from the super layer

I am using the generic code (from the iOS Fireworks demo) in a slightly modified way. I have the following UIView subclass. I want the fireworks to appear at the point the user touches (rather than hard) and reproduce the length of CAEmitterLayer / CAEmitterCells'. Instead, it starts immediately when I add it to addSublayer - for example, I'm sure it's intended. However, I would like to use it in a slightly different way. Is there a way I can change this so there is a CATransaction with a completion block (to remove theFromSuperlayer) or something like that? Any ideas are appreciated.

 #import "FireworksView.h"

    @implementation FireworksView

 - (void)launchFirework{

    //Load the spark image for the particle

    CAEmitterLayer *mortor = [CAEmitterLayer layer];
    mortor.emitterPosition = CGPointMake(self.bounds.size.width/2, self.bounds.size.height*(.75));
    mortor.renderMode = kCAEmitterLayerAdditive;

    //Invisible particle representing the rocket before the explosion
    CAEmitterCell *rocket = [CAEmitterCell emitterCell];
    rocket.emissionLongitude = -M_PI / 2;
    rocket.emissionLatitude = 0;
    rocket.lifetime = 1.6;
    rocket.birthRate = 1;
    rocket.velocity = 400;
    rocket.velocityRange = 100;
    rocket.yAcceleration = 250;
    rocket.emissionRange = M_PI / 4;
    rocket.color = CGColorCreateCopy([UIColor colorWithRed:.5 green:.5 blue:.5 alpha:.5].CGColor);
    rocket.redRange = 0.5;
    rocket.greenRange = 0.5;
    rocket.blueRange = 0.5;

    //Name the cell so that it can be animated later using keypath
    [rocket setName:@"rocket"];

    //Flare particles emitted from the rocket as it flys
    CAEmitterCell *flare = [CAEmitterCell emitterCell];
    flare.contents = (id)[UIImage imageNamed:@"tspark.png"].CGImage;
    flare.emissionLongitude = (4 * M_PI) / 2;
    flare.scale = 0.4;
    flare.velocity = 100;
    flare.birthRate = 45;
    flare.lifetime = 1.5;
    flare.yAcceleration = 350;
    flare.emissionRange = M_PI / 7;
    flare.alphaSpeed = -0.7;
    flare.scaleSpeed = -0.1;
    flare.scaleRange = 0.1;
    flare.beginTime = 0.01;
    flare.duration = 0.7;

    //The particles that make up the explosion
    CAEmitterCell *firework = [CAEmitterCell emitterCell];
    firework.contents = (id)[UIImage imageNamed:@"tspark.png"].CGImage;
    firework.birthRate = 9999;
    firework.scale = 0.6;
    firework.velocity = 130;
    firework.lifetime = 2;
    firework.alphaSpeed = -0.2;
    firework.yAcceleration = 80;
    firework.beginTime = 1.5;
    firework.duration = 0.1;
    firework.emissionRange = 2 * M_PI;
    firework.scaleSpeed = -0.1;
    firework.spin = 2;

    //Name the cell so that it can be animated later using keypath
    [firework setName:@"firework"];

    //preSpark is an invisible particle used to later emit the spark
    CAEmitterCell *preSpark = [CAEmitterCell emitterCell];
    preSpark.birthRate = 80;
    preSpark.velocity = firework.velocity * 0.70;
    preSpark.lifetime = 1.7;
    preSpark.yAcceleration = firework.yAcceleration * 0.85;
    preSpark.beginTime = firework.beginTime - 0.2;
    preSpark.emissionRange = firework.emissionRange;
    preSpark.greenSpeed = 100;
    preSpark.blueSpeed = 100;
    preSpark.redSpeed = 100;

    //Name the cell so that it can be animated later using keypath
    [preSpark setName:@"preSpark"];

    //The 'sparkle' at the end of a firework
    CAEmitterCell *spark = [CAEmitterCell emitterCell];
    spark.contents = (id)[UIImage imageNamed:@"tspark.png"].CGImage;
    spark.lifetime = 0.05;
    spark.yAcceleration = 250;
    spark.beginTime = 0.8;
    spark.scale = 0.4;
    spark.birthRate = 10;

    preSpark.emitterCells = [NSArray arrayWithObjects:spark, nil];
    rocket.emitterCells = [NSArray arrayWithObjects:flare, firework, preSpark, nil];
    mortor.emitterCells = [NSArray arrayWithObjects:rocket, nil];

    [self.layer addSublayer:mortor];
        }

      

+3


source to share


2 answers


The answer to this question is: using CAEmitter, NO WAY is a delegate, etc. - to stop the emitter when it completes the cycle. The only thing you can do is gracefully remove it from the layer if you think it needs to be removed.



+2


source


Ok, so I was able to achieve this by creating an animation with a delegate that fired along with the emitter. in animationDidStop I made a for loop that went through my view hierarchy and looked for emitters and removed them. it's a buggy and I still want a real solution, but it works for now.



for (CALayer *layer in _plusButton.layer.sublayers) {
    if (layer.class == [CAEmitterLayer class]) {
        [layer removeFromSuperlayer];
    }

}

      

+1


source







All Articles