NEW: Learn to build the incredible iOS 15 Weather app today! >>

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

   

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

1      

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

1      

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

   

Hacking with Swift is sponsored by Sentry

SPONSORED With Sentry’s error and performance monitoring for iOS, you see mobile vitals that actually matter, can solve any latency issues quickly, and learn how each release is performing over time.

Learn 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.