Search code examples
swiftswiftuisprite-kitfocustvos

Handling focus changes in tvOS SpriteKit app, where scene is embedded in a SwiftUI SpriteView


I'm having a mare trying to receive TV remote navigation (via the focus engine) in my SpriteKit game.

I've got a SwiftUI tvOS app with the following heirarchy:

struct SwatchGridSceneView: View {
    
    private let scene = SwatchGridScene()
    
    var body: some View {
        GeometryReader { geometry in
            SpriteView(scene: scene)
                .frame(width: geometry.size.width, height: geometry.size.height)
        }
    }
}

@main
struct ColourGameApp: App {
    var body: some Scene {
        WindowGroup {
            SwatchGridSceneView()
        }
    }
}


class SwatchGridScene: SKScene {
    ... contains 15 child nodes that are arranged in a 3x5 grid.
}

According to the limited docs I've found, I would expect didUpdateFocus to be called on the scene, allowing me to react to navigation with the TV remote, however, this is not called. I've found some info that states that the focus engine needs 'piping through' to the SpriteKit layer but the only examples for that are for UIKit, there's barely anything on SwiftUI and everything I have found hasn't worked.

In terms of a minimum reproducable example, the above (with code to add 15 basic ShapeNodes) works for this.

How can I configure the focus engine so that I may move between the sprite nodes in the grid using the Apple TV remote?


Solution

  • Turns out this was a case of setting isUserInteractionEnabled to true on the SKNode subclass. Whilst canBecomeFocused was already true, the various focus engine callbacks weren't being hit as the user was not permitted to interact with the node at all.

    For me, this comes to mind quickly when working on iOS, but I hadn't quite made the association for tvOS as the fact that navigating with the remote is still user interaction went straight over my head.