我想在两个场景之间切换:
class TestGameScene: SKScene {
override func didMove(to view: SKView) {
size = view.frame.size
scaleMode = .resizeFill
let textNode = SKLabelNode(text: "Game Scene")
textNode.position.x = size.width / 2
textNode.position.y = size.height / 2
addChild(textNode)
}
}
到
class TestGameOverScene: SKScene {
override func didMove(to view: SKView) {
size = view.frame.size
scaleMode = .resizeFill
backgroundColor = .red
let textNode = SKLabelNode(text: "Game Over")
textNode.position.x = size.width / 2
textNode.position.y = size.height / 2
addChild(textNode)
}
}
我目前正在通过
TestGameScene
展示 SpriteView
:
struct ContentView: View {
var body: some View {
SpriteView(scene: TestGameScene())
}
}
为了过渡到 Game Over 场景,我覆盖了
touchesBegan(_:with:)
中的 TestGameScene
以呈现 Game Over 场景,如下所示:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
view!.presentScene(TestGameOverScene(), transition: .fade(withDuration: 1.0))
}
虽然这有效,但如果应用程序进入后台,
TestGameOverScene
就会被取消初始化,从而导致游戏结束场景消失。使用 SpriteView 时有没有办法防止这种情况发生,或者有更好的方法在两个场景之间进行转换?我想使用 SpriteKit 提供的精美过渡,例如。 .doorsOpenVertical(withDuration: 0.5)
等等等等
在尝试了一些想法之后,我想出了可行的解决方案,但是,我希望对这种方法的好坏进行一些批评/分析,因为我对内存管理不太了解。
此类为
ContentView
提供了使用 SpriteView
渲染的场景。这是一个已发布的属性,当它发生更改时,应该通知 SwiftUI。
final class SceneProvider: ObservableObject {
@Published var scene: SKScene
init() {
let initialScene = TestGameScene()
self.scene = initialScene
initialScene.viewState = self
}
}
添加了对 SwiftUI 呈现的场景的绑定/引用。我们将更新此引用到新呈现的场景以通知 SwiftUI。
class TestGameScene: SKScene {
unowned var viewState: SceneProvider!
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let sceneToPresent = TestGameOverScene()
viewState.scene = sceneToPresent // << we do this so SwiftUI updates
view!.presentScene(sceneToPresent, transition: .fade(withDuration: 1.0))
}
// .. Rest is the same
}
从这里,我也许可以创建一个自定义的
SKScene
子类来封装所有这些行为。
当然,
struct ContentView: View {
@StateObject var sceneProvider = SceneProvider() // << @StateObject ensures the container for the presented scene, ie. SceneProvider, isn't deallocated
var body: some View {
SpriteView(scene: sceneProvider.scene)
}
}
使用这种方法,当
TestGameScene
出现时,TestGameOverScene
会被取消初始化 - 这很好(我认为)。除此之外,即使您转到后台并返回,SwiftUI 也会维护新呈现的场景,因为 @Published
属性和 @StateObject
使 SwiftUI 保持最新状态。
由于
SceneProvider
仅保留一个场景,因此我们不会有多个场景只占用内存空间 - 这又很好(我知道这肯定很好)。
希望得到一些对此的反馈。