簡體   English   中英

如何讓 SKEmitterNode 在 SwiftUI 中工作?

[英]How can I get SKEmitterNode to work in SwiftUI?

我試圖更新的顏色SKEmitterNode一個內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)
    }
  }

現在 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 並以這種方式訪問​​它。

為了使 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)
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM