如何让 SKEmitterNode 在 SwiftUI 中工作? [英] How can I get SKEmitterNode to work in SwiftUI?

查看:37
本文介绍了如何让 SKEmitterNode 在 SwiftUI 中工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to update the colour of an SKEmitterNode within a UIViewRepresentable. The hue value is passed in from the state on the parent View, and the emitter colour should update when the hue value in the parent state updates.

它最初显示,尽管它在第一次调用 updateUIView 时更新,但它不会响应任何后续调用,即使该函数肯定会使用 hue<的新值被调用/code> 每次.

It initially displays, and although it updates on the first call to updateUIView it does not respond to any subsequent calls, even though the function definitely gets called with the new value of hue each time.

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

Has anyone any idea why the emitter won't update? I'm at the hair-tearing-out stage...

  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 了.

Now that 11 is out I can finally play with Swift UI.

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

The problem being experienced is that your UIViewRepresentable is a struct.

结构的工作方式是它们在写入时复制.

The way structs work is they are copy on write.

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

I am going to assume that in your scene delegate, you are not reassigning the struct in your root controller when you set the hue.

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

You need to move your code into class for best results (Not the coordinator, they are used for application flow. Research Coordinator Pattern for more info.)

最好的课程是你的 SKScene.

The best class would be your SKScene.

我建议创建一个 GameScene 类并将您的 sks 文件更改为指向它.

I recommend making a GameScene class and changing your sks file to point to it.

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

You can then create a function to this game scene class that will allow you to alter the emitter without altering the struct.

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 将复制值.

The reason why this works is because on copy, the view will copy the pointer, where as hue will copy the value.

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

If you need to do things in the updateUIView, you can always cast uiView.scene to GameScene and access it that way.

这篇关于如何让 SKEmitterNode 在 SwiftUI 中工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆