CAEmitterCell does not account for changes in birth

I would like to create a particle effect that only emits while the user touches the screen, but I cannot change the CAEmitterCell birthRate property when set to a non-zero value.

I have a subclass of UIView that sets my CAEmitterLayer and my CAEmitterCell exactly the way I want them. I define two properties of this class:

@property (strong, nonatomic) CAEmitterLayer *emitterLayer; @property (strong, nonatomic) CAEmitterCell *emitterCell; 

Then, in my opinion, the controller, I track the touches by setting the position of the emitterLayer and the birth rate of the emitterCell:

 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; CGPoint tappedPt = [touch locationInView:touch.view]; NSLog(@"began x:%fy:%f",tappedPt.x, tappedPt.y); emitterView.emitterCell.birthRate = 42; emitterView.emitterLayer.emitterPosition = tappedPt; } -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; CGPoint tappedPt = [touch locationInView:touch.view]; NSLog(@"moved x:%fy:%f",tappedPt.x, tappedPt.y); emitterView.emitterLayer.emitterPosition = tappedPt; } -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{ NSLog(@"ending %f", emitterView.emitterCell.birthRate); emitterView.emitterCell.birthRate = 0.00; NSLog(@"ended %f", emitterView.emitterCell.birthRate); } 

The log says that emitterView.emitterCell.birthRate is changing:

 began x:402.000000 y:398.500000 ending 42.000000 ended 0.000000 

When I touch the screen, the emitter starts as expected, the layer follows the touch, but when I finish the touch, the emitter cell gladly emits any value that was originally set (the value is set in touchhesBegan). No matter what I do, I seem to be unable to change the birth rate after a non-zero value is set. The log reports that the values ​​are set correctly, but the emitter continues to emit.

However, if I changed the touchesEnded method to change the position of the layer, after I set the birthRate value to emitterCell, everything will work as expected:

 -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{ UITouch *touch = [touches anyObject]; CGPoint tappedPt = [touch locationInView:touch.view]; NSLog(@"began x:%fy:%f",tappedPt.x, tappedPt.y); NSLog(@"ending %f", emitterView.emitterCell.birthRate); emitterView.emitterCell.birthRate = 0.0; NSLog(@"ended %f", emitterView.emitterCell.birthRate); emitterView.emitterLayer.emitterPosition = tappedPt; } 

Can someone explain why?

+7
source share
2 answers

I don’t know why it behaves a little strange, but I found out that using the encoding key value solves the problem and the cell stops emitting:

Assuming your CAEmitterLayer is "yourEmitterLayer" and you have a CAEmitterCell called "yourEmitterCell", this will stop the emission if it is placed inside touchesEnded:

 [yourEmitterLayer setValue:[NSNumber numberWithInt:0] forKeyPath:@"emitterCells.yourEmitterCell.birthRate"]; 
+6
source

To stop particle emission, you need to set the birthRate property of the birthRate instance to 0, although it was originally set to the CAEmitterCell instance ... You don't know why, but it works.

Swift 3 example:

 func emitParticles() { let particlesEmitter = CAEmitterLayer() particlesEmitter.emitterPosition = center particlesEmitter.emitterShape = kCAEmitterLayerCircle particlesEmitter.emitterSize = CGSize(width: 50, height: 50) particlesEmitter.renderMode = kCAEmitterLayerAdditive let cell = CAEmitterCell() cell.birthRate = 15 cell.lifetime = 1.0 cell.color = bubble.color.cgColor cell.velocity = 150 cell.velocityRange = 50 cell.emissionRange = .pi cell.scale = 0.1 cell.scaleSpeed = -0.1 cell.contents = UIImage(named: "particle")?.cgImage particlesEmitter.emitterCells = [cell] layer.addSublayer(particlesEmitter) DispatchQueue.main.asyncAfter(deadline: .now() + 1) { particlesEmitter.birthRate = 0 } } 
+2
source

All Articles