Hey,
Here's some code that will let you embed a SpriteKit SKScene in a SwiftUI view hierarchy.
Let's start off with a sample scene:
import SpriteKit
class GameScene: SKScene {
override func didMove(to view: SKView) {
backgroundColor = .darkGray
physicsBody = SKPhysicsBody(edgeLoopFrom: frame)
}
override func mouseDown(with event: NSEvent) {
let location = event.location(in: self)
let size = CGSize(width: 40, height: 40)
let cube = SKShapeNode(rectOf: size)
cube.fillColor = .red
cube.physicsBody = SKPhysicsBody(rectangleOf: size)
cube.position = location
addChild(cube)
}
}
Here are the views that will allow you to use it in SwiftUI pre-Big-Sur:
struct GameView: View {
let scene: SKScene
var body: some View {
GeometryReader { proxy in
GameViewRepresentable(scene: scene, proxy: proxy)
}
}
}
struct GameViewRepresentable: NSViewRepresentable {
let scene: SKScene
let proxy: GeometryProxy
func makeCoordinator() -> Coordinator {
Coordinator()
}
func makeNSView(context: Context) -> SKView {
scene.size = proxy.size
context.coordinator.scene = scene
let view = SKView()
view.presentScene(scene)
return view
}
func updateNSView(_ nsView: SKView, context: Context) {
context.coordinator.resizeScene(proxy: proxy)
}
class Coordinator: NSObject {
weak var scene: SKScene?
func resizeScene(proxy: GeometryProxy) {
scene?.size = proxy.size
}
}
}
These will size the scene properly for the view's size, and resize it when the view's size changes. You can use them by passing your SKScene to the init(scene:)
initializer of GameView
like this:
struct ContentView: View {
var body: some View {
GameView(scene: GameScene())
}
}
Hope that helped!
--Jakub