Chewie The Chorkie
Chewie The Chorkie

Reputation: 5234

What is the proper way to end a CAEmitterLayer in Swift?

I've mostly seen examples of continuous emitters in Swift, and I've found one example in Obj-C by setting the birthRates of the emitter cells to 0.0, but it doesn't seem to work, so I must be doing something wrong. In my example, I can see the message that the birth rate was set to 0 sixteen times, but the particles continue to flow endlessly.

@IBAction func particleBtnAction(_ sender: Any) {

    let emitter = CAEmitterLayer()
    emitter.emitterPosition = CGPoint(x: self.view.frame.size.width / 2, y: -10)
    emitter.emitterShape = kCAEmitterLayerLine
    emitter.emitterSize = CGSize(width: self.view.frame.size.width, height: 2.0)
    emitter.emitterCells = generateEmitterCells()
    self.view.layer.addSublayer(emitter)

    // perform selector after 1.5 seconds when particles start
    perform(#selector(endParticles), with: emitter, afterDelay: 1.5)

}

private func generateEmitterCells() -> [CAEmitterCell] {

    var cells:[CAEmitterCell] = [CAEmitterCell]()
    for index in 0..<16 {
        let cell = CAEmitterCell()
        cell.birthRate = 4.0
        cell.lifetime = 1.0
        cell.lifetimeRange = 0
        cell.velocity = 0.7
        cell.velocityRange = 0
        cell.emissionLongitude = CGFloat(Double.pi)
        cell.emissionRange = 0.5
        cell.spin = 3.5
        cell.spinRange = 0
        cell.scaleRange = 0.25
        cell.scale = 0.1
        cells.append(cell)
    }
    return cells
}

@objc func endParticles(emitterLayer:CAEmitterLayer) {

    for emitterCell in emitterLayer.emitterCells! {
        emitterCell.birthRate = 0.0
        print("birth rate set to 0")
    }

}

Upvotes: 6

Views: 2273

Answers (4)

Marcin Żmigrodzki
Marcin Żmigrodzki

Reputation: 393

What worked for me is this:

let emmitter = CAEmitterLayer()
let cell = makeCell()
emmitter.emitterCells = [cell]
view.layer.addSublayer(emmitter)

 DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
    emmitter.removeFromSuperlayer()
 }

Upvotes: 0

user3408691
user3408691

Reputation: 93

You might try setting the isHidden property when you want to endParticles

emitter.isHidden = true

But note that all the cells instantly vanish, no matter when they were emitted, or their lifetime.

Another possibility would be to set all the scale related properties to 0, and then the lifetime and birthrate would not matter, as newly emitted cells would not be visible.

cell.scaleSpeed = 0
cell.scaleRange = 0
cell.scale = 0

Upvotes: 0

ajrlewis
ajrlewis

Reputation: 3058

Setting the CAEmitterLayer's lifetime to zero stops any new emitterCells being emitted:

@objc func endParticles(emitterLayer:CAEmitterLayer) {
    emitterLayer.lifetime = 0.0
}

Upvotes: 12

Chewie The Chorkie
Chewie The Chorkie

Reputation: 5234

You can use key paths to assign a name to each cell and loop through them, changing each cell's property when you want to change them:

private func generateEmitterCells() -> [CAEmitterCell] {

    var cells:[CAEmitterCell] = [CAEmitterCell]()
    for index in 0..<16 {
        let cell = CAEmitterCell()
        cell.birthRate = 4.0
        cell.lifetime = 1.0
        cell.lifetimeRange = 0
        cell.velocity = 0.7
        cell.velocityRange = 0
        cell.emissionLongitude = CGFloat(Double.pi)
        cell.emissionRange = 0.5
        cell.spin = 3.5
        cell.spinRange = 0
        cell.scaleRange = 0.25
        cell.scale = 0.1
        cell.name = "cell\(index)" // cell name
        cells.append(cell)
    }
    return cells
}

@objc func endParticles(emitterLayer:CAEmitterLayer) {

    for i in 0..<(emitterLayer.emitterCells?.count ?? 0){

        emitterLayer.setValue(0.0, forKeyPath: "emitterCells.cell\(i).birthRate")
        print("birth rate set to 0")

    }

}

Upvotes: 0

Related Questions