问题
SpriteView
似乎没有将state属性传递给SpriteView(scene:isPaused:)
初始化器来暂停SKScene
。
示例项目
我创建了一个运行在iOS 15模拟器上的sample Xcode 13 project on GitHub,其中ContentView
带有@State var paused
属性,该属性发送给子SpriteView(scene: scene, isPaused: paused)
。状态属性通过“Paused:”按钮进行更改。属性更改,按钮上的文本更新,但SpriteView从未暂停场景。
看起来SpriteView没有拾取更新,也没有暂停它内部的底层SKView和SKScene。
x1c 0d1x的数据
所有相关代码都在ContentView.swift中:
import SwiftUI
import SpriteKit
class GameScene: SKScene, ObservableObject {
@Published var updates = 0
private let label = SKLabelNode(text: "Updates in SKScene:\n0")
override func didMove(to view: SKView) {
addChild(label)
label.numberOfLines = 2
}
override func update(_ currentTime: TimeInterval) {
updates += 1
label.text = "Updates in SKScene:\n\(updates)"
}
}
struct ContentView: View {
@State private var paused = false
@StateObject private var scene: GameScene = {
let scene = GameScene()
scene.size = CGSize(width: 300, height: 400)
scene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
scene.scaleMode = .fill
return scene
}()
var body: some View {
if #available(iOS 15.0, *) {
print(Self._printChanges())
}
return ZStack {
SpriteView(scene: scene, isPaused: paused).ignoresSafeArea()
VStack {
Text("Updates from SKScene: \(scene.updates)").padding().foregroundColor(.white)
Button("Paused: \(paused)" as String) {
paused.toggle()
}.padding()
Spacer()
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
字符串
重启问题
我还创建了一个second GitHub project,它与第一个类似,但它也有一个“重启”按钮,显示了同样的问题。
当按下“重启”按钮时,应该会重新创建SKScene
。SKScene会在SceneStore
和ContentView
的Text
视图中重新创建(为场景的name
属性分配了新的时间),但SpriteView
不会更改场景。
SpriteView似乎将初始场景保留在内存中,并且不会让它去用新场景替换它。这可以在控制台中看到,通过点击重新启动按钮两次并查找类似“-- Scene 7:49:44 PM deinit --"的内容。
场景内@Published var updates = 0
属性的更新也会停止(在屏幕顶部),因为创建的新场景没有添加到视图中,所以SKScene.didMove(to view:)
方法永远不会被调用。
的
下面是ContentView.swift中的相关代码:
import SwiftUI
import SpriteKit
class GameScene: SKScene, ObservableObject {
@Published var updates = 0
private let label = SKLabelNode(text: "Updates in SKScene:\n0")
override func didMove(to view: SKView) {
addChild(label)
label.numberOfLines = 4
label.position = CGPoint(x: 0, y: -100)
}
override func update(_ currentTime: TimeInterval) {
updates += 1
label.text = "Updates in SKScene:\n\(updates)\nScene created at:\n\(name!)"
}
deinit {
print("-- Scene \(name!) deinit --")
}
}
class SceneStore : ObservableObject {
@Published var currentScene: GameScene
init() {
currentScene = SceneStore.createScene()
}
func restartLevel() {
currentScene = SceneStore.createScene()
}
// MARK: - Class Functions
static private func createScene() -> GameScene {
let scene = GameScene()
scene.size = CGSize(width: 300, height: 400)
scene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
scene.scaleMode = .fill
scene.name = Date().formatted(date: .omitted, time: .standard)
return scene
}
}
struct ContentView: View {
@EnvironmentObject private var sceneStore: SceneStore
@EnvironmentObject private var scene: GameScene
@State private var paused = false
var body: some View {
if #available(iOS 15.0, *) {
print(Self._printChanges())
}
return ZStack {
SpriteView(scene: scene, isPaused: paused).ignoresSafeArea()
VStack {
Text("Updates from SKScene: \(scene.updates)").padding().foregroundColor(.white)
Text("Scene created at: \(scene.name!)" as String).foregroundColor(.white)
Button("Restart") {
sceneStore.restartLevel()
}.padding()
Button("Paused: \(paused)" as String) {
paused.toggle()
}
Spacer()
}
}
}
}
型
问题/解决方法?
我错过了什么吗?或者这是一个bug?如果是,有什么解决方法吗?
2条答案
按热度按时间3htmauhk1#
您是正确的,
isPaused
在传递给SpriteView
时似乎不会影响暂停状态。为了解决这个问题,我使用了:
字符串
第二个问题是一部分
SpriteView
问题和一部分ObservableObject
问题。需要知道的重要一点是,嵌套的
ObservableObject
s不会传播它们的状态,除非您手动调用objectWillChange.send()
。因此,我使用了合并来跟踪子对象上的@Published
updates
变量,并在有更新时调用objectWillChange
。此外,当有一个新场景时,
setupCombine
会被再次调用,这不仅会传播更新,还会提醒View
场景已经更改。最后,因为场景不会被重新加载,所以我使用了一个
id
,它会在生成新的GameScene
时发生变化--这会强制SwiftUI创建一个新的SpirteView
。型
qcuzuvrc2#
您可以查看Pausing a sprite kit scene
基本上你每次点击暂停按钮都要暂停场景
字符串
这将暂停您的更新