[tvOS] Reacting to button taps

I've just started working on my first SpriteKit game that will eventually run on both tvOS and iOS and am looking at how to build a "button". So far, I've got a custom node that looks like:

class MyButton: SKSpriteNode {
  ...

#if os(tvOS)
    override var canBecomeFocused: Bool {
        true
    }

    override func didUpdateFocus(...) {
       ...
    }
#endif  
}

The above let me nicely handle focus changes in tvOS and now I'm looking at reacting to selecting the button.

Searching around, all the articles/questions/posts are from 2015-2016 - which is a LOOOONG time ago. Most of the guidance appears to be to add a tap gesture recognizer in the owning scene and getting the scene to hand it off to the button. That seems pretty brittle and I'd much prefer if the button itself is responsible for its own tap management.

So, I guess my question is whether I should just add a gesture recognizer to my custom button class? Is this inefficient if I end up having 7-8 buttons on the screen and each one has its own gesture recognizer?

Somewhat related, all of the 10-year-old advice is that if we add recognizers to scenes, then they need to be removed from the view controller... however, in the modern day world with SwiftUI, my project doesn't even have a view controller (yet, anyway)... what gesture recognizer lifecycle management do I need in a SpriteKit scene that is presented within a SpriteKitView?

Or, is there a better way? I was kind of hoping that overriding pressesBegan() (or something similar) in my custom button might have been triggered on tvOS (like touchesBegan() lets me manage touches for the iOS variant of my app)

Any pointers or suggestions would be gladly received. Thanks.

Answered by DTS Engineer in 823174022

Hello,

Re: "So, I guess my question is whether I should just add a gesture recognizer to my custom button class? Is this inefficient if I end up having 7-8 buttons on the screen and each one has its own gesture recognizer?"

Yes and no

Re: "what gesture recognizer lifecycle management do I need in a SpriteKit scene that is presented within a SpriteKitView?"

I'll assume you're referring to SpriteView, and like a typical SwiftUI View you add a .gesture modifier.

Re: "Or, is there a better way?"

Maybe?

Do your buttons have to be rendered in the SpriteView or could they be in a container View instead as a Button? You might find this separation of concerns cleaner, and possibly improves MVC clarity.

Do you really need SwiftUI for building a SpriteKit game?

Hello,

Re: "So, I guess my question is whether I should just add a gesture recognizer to my custom button class? Is this inefficient if I end up having 7-8 buttons on the screen and each one has its own gesture recognizer?"

Yes and no

Re: "what gesture recognizer lifecycle management do I need in a SpriteKit scene that is presented within a SpriteKitView?"

I'll assume you're referring to SpriteView, and like a typical SwiftUI View you add a .gesture modifier.

Re: "Or, is there a better way?"

Maybe?

Do your buttons have to be rendered in the SpriteView or could they be in a container View instead as a Button? You might find this separation of concerns cleaner, and possibly improves MVC clarity.

Do you really need SwiftUI for building a SpriteKit game?

Re: "So, I guess my question is whether I should just add a gesture recognizer to my custom button class? Is this inefficient if I end up having 7-8 buttons on the screen and each one has its own gesture recognizer?"

Yes and no

I've been testing a few patterns and I think I'm coming to the conclusion that I'll end up having a single recognizer in each scene that finds/hands-off to the appropriate button. I was kinda hoping to compartmentalise it so that each button is able to deal with that but it feels like I'm fighting the framework if I do that.

Re: "what gesture recognizer lifecycle management do I need in a SpriteKit scene that is presented within a SpriteKitView?"

I'll assume you're referring to SpriteView, and like a typical SwiftUI View you add a .gesture modifier.

Sorry, I was a bit vague there... I was more talking about how the general guidance for gesture recognizer lifecycle is to add them to the view in didMove(to:) and then remove them just before transitioning to a new scene. Is this still the advice in a SwiftUI world? It seems so, but I wasn't sure if this had changed over time with the introduction of SwiftUI containing views.

Do your buttons have to be rendered in the SpriteView or could they be in a container View instead as a Button? You might find this separation of concerns cleaner, and possibly improves MVC clarity.

This was definitely one of the options I was exploring too. For the buttons that are a bit "chrome"-like, it kinda makes sense... but for the "in-game" buttons, it would mean splitting the game behaviour across SpriteKit and the hosting UI container (which I think would end up causing me more pain)

Do you really need SwiftUI for building a SpriteKit game?

Nah, definitely not. Xcode just happened to generate SwiftUI for me when I created the project. As it turns out, I'm not really "using" SwiftUI capability at all... it is just a dumb container for my scenes.

Many thanks for your feedback. Much appreciated.

[tvOS] Reacting to button taps
 
 
Q