UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: SwiftUI + SpriteKit + macOS Catalina 10.15?

Forums > SwiftUI

Hi All, I've been working on a Swift/SpriteKit project for a couple of years, with basically no UI. I've just gone through Paul's book on SwiftUI -- wow. I already have some nice UI in place. But I'm having trouble integrating all that nice UI into my app. Paul published an example for integrating SpriteKit with SwiftUI, but it's only for iOS, and I don't have any idea how to translate that to my needs. Does anyone know how to accomplish the same in a macOS app (Pre-Big Sur)? Cheers

2      

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

3      

Wow, thanks so much! It works perfectly. I would never have figured that out on my own, thanks again -- Rob

3      

I'm happy it helped you. The flexibility you get by being able to mix SwiftUI with the native frameworks really is incredible.

2      

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.