【问题标题】:How can I get SKEmitterNode to work in SwiftUI?如何让 SKEmitterNode 在 SwiftUI 中工作?
【发布时间】:2019-09-15 22:11:17
【问题描述】:

我正在尝试更新 UIViewRepresentableSKEmitterNode 的颜色。色调值是从父 View 上的状态传入的,当父状态的色调值更新时,发射器颜色也应该更新。

它最初显示,尽管它在第一次调用 updateUIView 时更新,但它不会响应任何后续调用,即使每次调用该函数时都会使用 hue 的新值。

有人知道为什么发射器不会更新吗?我正处于脱发阶段......

  import SwiftUI
  import UIKit
  import SpriteKit

  struct EmitterView: UIViewRepresentable {
    private let view = SKView()

    let scene = SKScene(fileNamed: "myScene")!
    var emitter: SKEmitterNode = SKEmitterNode()
    var hue: Double

    func makeUIView(context: UIViewRepresentableContext<EmitterView>) -> SKView {

      // Lets make it manually
      emitter.particleTexture = SKTexture(imageNamed: "spark")
      emitter.particleBirthRate = 80
      emitter.particleLifetime = 2.5
      emitter.particlePositionRange = CGVector(dx: 200, dy: 150)
      emitter.particleScale = 0.2
      emitter.particleScaleSpeed = 0.45
      emitter.particleColor = SKColor.blue
      emitter.particleColorBlendFactor = 1.0

      scene.addChild(emitter)
      view.presentScene(scene)

      return view
    }

    func updateUIView(_ uiView: SKView, context: UIViewRepresentableContext<EmitterView>) {

      let color: SKColor = SKColor(
        hue: CGFloat(hue),
        saturation: 1.0,
        brightness: 1.0,
        alpha: 1.0
      )

      print("Hue is now", hue)

      emitter.resetSimulation()
      emitter.particleColor = color
    }
  }

  struct EmitterView_Previews: PreviewProvider {
    static var previews: some View {
      EmitterView(hue: 0.5)
    }
  }

【问题讨论】:

    标签: ios sprite-kit swiftui skemitternode uiviewrepresentable


    【解决方案1】:

    现在 11 出来了,我终于可以玩 Swift UI了。

    遇到的问题是您的UIViewRepresentable 是一个结构。

    结构的工作方式是写入时复制。

    我将假设在您的场景委托中,当您设置色调时,您不会重新分配根控制器中的结构。

    您需要将代码移入类以获得最佳结果(不是协调器,它们用于应用程序流。研究协调器模式以获取更多信息。)

    最好的课程是你的 SKScene。

    我建议创建一个 GameScene 类并更改您的 sks 文件以指向它。

    然后您可以为此游戏场景类创建一个函数,该函数将允许您在不更改结构的情况下更改发射器。

    import SwiftUI
    import UIKit
    import SpriteKit
    
    struct EmitterView: UIViewRepresentable {
        private let view = SKView()
        let scene = GameScene(fileNamed: "myScene")!
        var hue : Double{
            get{
                return scene.hue
            }
            set{
                scene.hue = newValue
            }
        }
        func makeUIView(context: UIViewRepresentableContext<EmitterView>) -> SKView {
            view.presentScene(scene)
            return view
        }
    
        func updateUIView(_ uiView: SKView, context: UIViewRepresentableContext<EmitterView>) {
    
    
        }
    }
    
    struct EmitterView_Previews: PreviewProvider {
        static var previews: some View{
              EmitterView()
        }
    }
    
    
    class GameScene : SKScene{
        var hue : Double = 0{
            didSet{
                let color: SKColor = SKColor(
                    hue: CGFloat(hue),
                    saturation: 1.0,
                    brightness: 1.0,
                    alpha: 1.0
                )
    
                print("Hue is now", hue)
    
                emitter.resetSimulation()
                emitter.particleColor = color
            }
        }
    
        var emitter: SKEmitterNode = SKEmitterNode()
        override func didMove(to view: SKView) {
            emitter.particleTexture = SKTexture(imageNamed: "spark")
            emitter.particleBirthRate = 80
            emitter.particleLifetime = 2.5
            emitter.particlePositionRange = CGVector(dx: 200, dy: 150)
            emitter.particleScale = 0.2
            emitter.particleScaleSpeed = 0.45
            emitter.particleColor = SKColor.blue
            emitter.particleColorBlendFactor = 1.0
            addChild(emitter)
        }
    
    }
    

    之所以可行,是因为在复制时,view 将复制指针,而 hue 将复制值。

    如果您需要在 updateUIView 中进行操作,您可以随时将 uiView.scene 转换为 GameScene 并以这种方式访问​​它。

    【讨论】:

    • 感谢您抽出宝贵时间查看此内容。一切都说得通,而且是一个干净的解决方案。
    • @raffjones 没问题,我应该在看到 struct 后早点发现它,但它让我忘记了。一旦我开始使用它并让编译器立即对我大喊 contentView 不可变,它就引发了它失败的原因。
    【解决方案2】:

    为了使 UIViewRepresentable 结构可变,请将 @Binding 前缀添加到 hue 变量。

    @Binding var hue: Double
    

    然后您可以通过以下方式从父视图更改粒子的颜色:

    struct ContentView: View {
        @State var hue: Double = 0.5
        var body: some View {
            VStack {
                EmitterView(hue: self.$hue)
                Slider(value: $hue)
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2020-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-23
      • 1970-01-01
      相关资源
      最近更新 更多