I would like to create a particle effect which is only emitting while the user touches the screen, but I cannot change the CAEmitterCell birthRate property once is set to a non zero value.
I have a subclass of UIView, which sets up my CAEmitterLayer and my CAEmitterCell just the way I want them. I am defining two properties on that class:
@property (strong, nonatomic) CAEmitterLayer *emitterLayer;
@property (strong, nonatomic) CAEmitterCell *emitterCell;
Then, in my view controller, I am tracking touches, setting the position of the emitterLayer, and emitterCell birthrate:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint tappedPt = [touch locationInView:touch.view];
NSLog(@"began x:%f y:%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:%f y:%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 reports that the emitterView.emitterCell.birthRate changes:
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 end the touch, the emitter cell happily emits whatever value was set initially set (the value set in touchesBegan). Whatever I do I cannot seem to be able to change the birthrate value once is set to a non zero value. Log reports that the values are set properly, but the emitter keeps emitting.
However, if I change the touchesEnded method to change the position of the layer, after I set the birthRate on emitterCell then everything works as expected:
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
CGPoint tappedPt = [touch locationInView:touch.view];
NSLog(@"began x:%f y:%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 please explain why?
To stop emitting the particles you have to set birthRate
property of CAEmitterLayer
instance to 0, although it was initially set on CAEmitterCell
instance... Not sure 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
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With