Search code examples
swiftcallbackstate-machinegameplay-kit

How do you update your UI when using a state machine


I'm using swifts stateMachine from gamePlayKit. It works great, but there is one thing I don't understand: The stateMachineseems to be its own isolated island; from what I can tell there is no way to pass in arguments or get callbacks. And this raises questions like, how do I update the UI?

Lets say I enter combat state:

 stateMachine.enter(CombatState.self)

There's no way to pass in an argument. Ok, fine. But then CombatState does its thing and when it's done it goes into another state. BUT, before that I need a callback to the view so that I can remove the units from the board lost in combat like so:

self.removeChildren(in: nodesOutOfAction)

But there's no way to send the nodes out of the stateMachine because there's no possible way to add a completion handler. So how do you work around this problem? To me the stateMacine is pointless as it can´t update the UI.

Its possible to access properties of the state like so:

stateMachine.enter(CombatState.self)
self.removeChildren(in: combatState.nodesToRemove)

But that can't be safe, right? Still, as this is the only option that I know of, this is how I solve it.


Solution

  • I totally recommend you check the DemoBots project from Apple.

    You should pass the entity reference on the State Initializer

    For example

    class CombatState: GKState {
    
        unowned var gameScene: GameScene
    
        required init(gameScene: GameScene) {
            self.gameScene = gameScene
        }
    
        override func didEnter(from previousState: GKState?) {
            gameScene.removeChildren(in: ...)
        }
    }
    

    With this logic you can decouple a lot of logic inside to the states.