ios - 如何让 SKEmitterNode 在 SwiftUI 中工作?
问题描述
我正在尝试更新SKEmitterNode
a 内的颜色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
将复制指针,而 ashue
将复制值。
如果您需要在 updateUIView 中进行操作,您可以随时将 uiView.scene 转换为 GameScene 并以这种方式访问它。
推荐阅读
- php - 使用 bootstrap 在同一行显示 3 篇文章
- django - 如何使用 InMemoryUploadedFile 在 Django 中获取视频缩略图?
- azure-logic-apps - Azure 数据网关和逻辑应用 - 存储 sql server 登录详细信息
- javascript - 类型“NumberSchema”上不存在属性“长度”
- docker - 使用来自 docker 的 openvino
- javascript - 更改 AWS cognito 登录 UI 中的文本
- javascript - 如何从在 AJAX 中创建的表中获取“innerText”内的项目总和?
- c# - 尝试从过程中获取数据时:PL/SQL - 数字或值错误
- css - 引导行大纲
- c++ - 为链接列表中的函数设置参数