Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

moonman239

Cancelled
Original poster
Mar 27, 2009
1,541
32
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.
 
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.
 
Last edited:
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.
 
Last edited:
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"];

 }
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.