在 Swift 中结束 CAEmitterLayer 的正确方法是啥?

Posted

技术标签:

【中文标题】在 Swift 中结束 CAEmitterLayer 的正确方法是啥?【英文标题】:What is the proper way to end a CAEmitterLayer in Swift?在 Swift 中结束 CAEmitterLayer 的正确方法是什么? 【发布时间】:2018-12-18 16:35:35 【问题描述】:

我主要在 Swift 中看到连续发射器的示例,并且我在 Obj-C 中找到了一个示例,将发射器单元的birthRates 设置为 0.0,但它似乎不起作用,所以我必须做错事。在我的示例中,我可以看到 16 次将出生率设置为 0 的消息,但粒子继续无休止地流动。

@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")
    


【问题讨论】:

看看这个库彗星怎么样:github.com/cruisediary/Comets 【参考方案1】:

CAEmitterLayerlifetime 设置为零会停止发出任何新的emitterCells

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

【讨论】:

那以后怎么重启发射? 您可以将emitterLayer.lifetime 设置为0 以外的值。您还可能希望在再次启动它时设置emitterLayer.beginTime = CACurrentMediaTime(),否则精灵可能会出现在您不希望它们出现的地方。 【参考方案2】:

您可以使用关键路径为每个单元格指定名称并循环访问它们,在您想要更改它们时更改每个单元格的属性:

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")

    


【讨论】:

不确定我是否会使用私有 API 来实现这一点。请参阅我的答案。【参考方案3】:

当你想结束粒子时,你可以尝试设置 isHidden 属性

emitter.isHidden = true

但请注意,所有的细胞都会立即消失,无论它们是什么时候发出的,也不管它们的生命周期。

另一种可能性是将所有与比例相关的属性设置为 0,然后寿命和出生率就无关紧要了,因为新发射的细胞将不可见。

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

【讨论】:

【参考方案4】:

对我有用的是:

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

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

【讨论】:

以上是关于在 Swift 中结束 CAEmitterLayer 的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

游戏结束后如何在 Swift SceneKit 游戏中启用广告?

Swift-摇动结束后查找位置

Swift XMLParser 检测元素结束

Kotlin Multiplatform (KMM) 中的对象在 Swift 函数中实例化。函数结束它的作用域。谁释放了对象?

Swift 3.0 中的 Spotify SDK:如何知道歌曲何时结束

Swift:在 nstimer 倒计时结束时转换到新的视图控制器 [重复]