首页 > 解决方案 > 如何让 SKEmitterNode 在 SwiftUI 中工作?

问题描述

我正在尝试更新SKEmitterNodea 内的颜色UIViewRepresentable。色调值是从父视图上的状态传入的,当父状态中的色调值更新时,发射器颜色应该更新。

它最初显示,尽管它在第一次调用时更新,但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)
    }
  }

标签: iossprite-kitswiftuiskemitternodeuiviewrepresentable

解决方案


现在 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将复制指针,而 ashue将复制值。

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


推荐阅读