Je rencontre un problème lors de la création d'une scène SpriteKit
dans SwiftUI
. J'ai créé ce projet initialement comme un projet SwiftUI
.
Voici le code que j'ai jusqu'à présent:
ContentView.Swift:
/// Where the UI content from SwiftUI originates from.
struct ContentView : View {
var body: some View {
// Scene
SceneView().edgesIgnoringSafeArea(.all)
}
}
SceneView.Swift:
/// Creates an SKView to contain the GameScene. This conforms to UIViewRepresentable, and so can be used within SwiftUI.
final class SceneView : SKView, UIViewRepresentable {
// Conformance to UIViewRepresentable
func makeUIView(context: Context) -> SKView {
print("Make UIView")
return SceneView(frame: UIScreen.main.bounds)
}
func updateUIView(_ uiView: SKView, context: Context) {
print("Update UIView")
}
// Creating scene
override init(frame: CGRect) {
super.init(frame: frame)
let scene = Scene(size: UIScreen.main.bounds.size)
presentScene(scene)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Scene.Swift:
/// The scene for the game in SpriteKit.
final class Scene : SKScene {
override func didMove(to view: SKView) {
super.didMove(to: view)
print("Scene didMove:")
}
}
Le problème est que la scène se recharge plusieurs fois, comme le montrent les journaux (car il y a print
s dans le code):
La scène a bougé:
Faire UIView
La scène a bougé:
Mettre à jour UIView
Comme vous pouvez le voir, Scene didMove:
est imprimé deux fois. Je veux seulement que cela soit appelé une fois, car je veux créer mes sprites ici. Des idées?
L'implémentation de votre SceneView
est incorrecte.
SwiftUI utilise des structures pour créer des vues dans son DSL - pas des vues.
Vous souhaitez créer un struct
conforme à UIViewRepresentable
.
struct SceneView: UIViewRepresentable {
let scene: SKScene
func makeUIView(context: Context) -> SKView {
// Let SwiftUI handle the sizing
return SKView(frame: .zero)
}
func updateUIView(_ uiView: SKView, context: Context) {
uiView.presentScene(scene)
}
}
Pour plus d'informations sur la façon de porter des vues basées sur UIKit
vers SwiftUI, consultez cette excellente vidéo WWDC 2019: Integrating SwiftUI .
Voici une vue de conteneur SpriteKit qui peut être utilisée de cette façon:
SpriteKitContainer(sceneName: "MainScene")
struct SpriteKitContainer : UIViewRepresentable {
let sceneName: String
class Coordinator: NSObject {
var scene: SKScene?
}
func makeCoordinator() -> Coordinator {
return Coordinator()
}
func makeUIView(context: Context) -> SKView {
let view = SKView(frame: .zero)
view.preferredFramesPerSecond = 60
view.showsFPS = true
view.showsNodeCount = true
//load SpriteKit Scene
guard let aScene = SKScene(fileNamed: sceneName)
else {
view.backgroundColor = UIColor.red
return view
}
aScene.scaleMode = .resizeFill
context.coordinator.scene = aScene
return view
}
func updateUIView(_ view: SKView, context: Context) {
view.presentScene(context.coordinator.scene)
}
}
#if DEBUG
struct ContentView_Previews : PreviewProvider {
static var previews: some View {
// Replace "MainScene" with your SpriteKit scene file name
SpriteKitContainer(sceneName: "MainScene")
.edgesIgnoringSafeArea(.all)
.previewLayout(.sizeThatFits)
}
}
#endif