Resolved Stop Core Animation emission immediately after start of emission

Discussion in 'iOS Programming' started by moonman239, May 29, 2015.

  1. moonman239 macrumors 68000

    Joined:
    Mar 27, 2009
    #1
    So, I'm running into a bit of a problem. My particle emitter (written using CAEmissionLayer + CAEmitterCell) is supposed to stop emitting almost immediately after emission has begun. I tried this:

    Code:
    [viewLayer addSublayer:layer];
    [emitterCell setBirthRate:0.0f];
    
    but that resulted in absolutely no emission occurring at all, as if viewLayer hadn't added a CAEmitterLayer.

    I'd like to be able to have the stopping of the emission happen in the same method in which it is begun, but so far haven't found the right way to do that. dispatch_after doesn't take millisecond values. I want the process to happen in just milliseconds so it appears as if the app had all these particles lined up and waiting to be emitted.
     
  2. moonman239, May 30, 2015
    Last edited: May 30, 2015

    moonman239 thread starter macrumors 68000

    Joined:
    Mar 27, 2009
    #2
    OK, so here's what I have thus far:

    Code:
        // Create a particle emission layer and set its properties.
        CAEmitterLayer *layer = [CAEmitterLayer layer];
        [layer setFrame:rect];
        layer.emitterPosition = self.view.center;
        layer.emitterSize = size;
        layer.emitterShape = kCAEmitterLayerCircle;
        layer.emitterZPosition = 0;
        layer.emitterMode = kCAEmitterLayerOutline;
        NSString *smallStarPath = [[NSBundle mainBundle] pathForResource:@"star copy" ofType:@"png"];
        id smallParticleImage = (__bridge id)[[UIImage imageWithContentsOfFile:smallParticlePath] CGImage];
        CAEmitterCell *emitterCell = [CAEmitterCell emitterCell];
        emitterCell.contents = smallParticleImage;
        emitterCell.birthRate = 10;
        emitterCell.lifetime = 2;
        emitterCell.lifetimeRange = 1;
        emitterCell.velocity = 1400;
        emitterCell.velocityRange = 20;
        emitterCell.emissionRange = 0.0f;
        // Create the trail.
        CAEmitterCell *trailEmitterCell = [CAEmitterCell emitterCell];
        trailEmitterCell.velocity = 0;
        trailEmitterCell.birthRate = 50;
        trailEmitterCell.lifetime = 0.4;
        trailEmitterCell.zAcceleration = 0;
        trailEmitterCell.emissionRange = 1.0f;
        NSString *trailImagePath = [[NSBundle mainBundle] pathForResource:@"r" ofType:@"png"];
        id trailImage = (__bridge id)[[UIImage imageWithContentsOfFile:trailImagePath] CGImage];
        trailEmitterCell.contents = trailImage;
        // [emitterCell setEmitterCells:[NSArray arrayWithObject:trailEmitterCell]];
        layer.emitterCells = [NSArray arrayWithObject:emitterCell];
        [viewLayer addSublayer:layer];
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(20 * 1000000)), dispatch_get_main_queue(), ^{
            emitterCell.birthRate = 0.0f;
        });
    
    However, the code in dispatch_after doesn't seem to get called. Why?

    UPDATE: Tried this, too, but the animation still wouldn't stop:
    Code:
        NSMethodSignature *birthRateSignature = [emitterCell methodSignatureForSelector:@selector(setBirthRate:)];
        NSInvocation *stopInvocation = [NSInvocation invocationWithMethodSignature:birthRateSignature];
        float zeroBirthRate = 0.0;
        [stopInvocation setArgument:&zeroBirthRate atIndex:0];
        NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.5 invocation:stopInvocation repeats:false];
    
    Update: As indicated by a symbolic breakpoint, setBirthRate is run twice.
     
  3. moonman239, May 30, 2015
    Last edited: May 30, 2015

    moonman239 thread starter macrumors 68000

    Joined:
    Mar 27, 2009
    #3
    CAEmitterCell is not respecting the birth rate change!

    OK, so I made my emitter layer a property of my view controller. Then, I created a method within the view controller's .m, which would set the birth
    rate to 0. I then added
    Code:
    [self performSelector:@selector(stopAnimation] withObject:nil afterDelay:0.4];
    
    immediately after the code that causes the emitter layer to be added to the view. The method code still doesn't actually seem to be doing anything, even though the birthRate property of the emitter cell is set to 0 (as confirmed by NSLog)!

    Edit: Turns out CAEmitterLayer and CAEmitterCell both have a "duration" property. Didn't help me, but maybe it will help someone else.
     
  4. moonman239 thread starter macrumors 68000

    Joined:
    Mar 27, 2009
    #4
    Problem resolved! Here is what I did:

    First, I created a UIView subclass. Then, with the help of Ray Wenderlich's emission tutorial, I slapped this code into the newly-created .m file:

    Code:
    -(void)playAnimation
    
    {
    
    layer.emitterSize = CGSizeMake(10, 10);
    
    layer.emitterShape = kCAEmitterLayerCircle;
    
    layer.emitterZPosition = 0;
    
    layer.emitterMode = kCAEmitterLayerOutline;
    
        [NSTimerscheduledTimerWithTimeInterval:0.5target:selfselector:@selector(stopAnimation) userInfo:nilrepeats:NO];
    
    layer.emitterPosition = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2);
    
    // Create an emitter cell for the little stars.
    
    NSString *smallStarPath = [[NSBundlemainBundle] pathForResource:@"star copy"ofType:@"png"];
    
    id smallStarImage = (__bridgeid)[[UIImageimageWithContentsOfFile:smallStarPath] CGImage];
    
    CAEmitterCell *emitterCell = [CAEmitterCellemitterCell];
    
    emitterCell.contents = smallStarImage;
    
    emitterCell.birthRate = 30;
    
    emitterCell.lifetime = 2;
    
    emitterCell.lifetimeRange = 1;
    
    emitterCell.velocity = 1400;
    
    emitterCell.velocityRange = 20;
    
    emitterCell.emissionRange = 0.0f;
    
    emitterCell.name = @"star";
    
    layer.emitterCells = [NSArrayarrayWithObject:emitterCell];
    
    }
    
    
    -(void)stopAnimation
    
     {
    
        [layersetValue:[NSNumbernumberWithInteger:0] forKeyPath:@"emitterCells.star.birthRate"];
    
     }
    
     

Share This Page