Search code examples
iossprite-kitstate-machinegameplay-kit

(Apple) GameplayKit State Machine implementation with SKScene


I've read up on the GameplayKit State Machine and the documentation explicitly mention Game UI as an example of usage. Im fully understanding the concept but I am unsure how to implement it while using SpriteKit.

Lets say I want 3 states. Menu, Gameplay and Game Over - All which display content to the SKScene. GameScene class extends SKScene. So it's impossible to turn GameScene into a state machine since we only can extend one class.

Should GameScene have a variable for a state machine with a reference to the SKScene, or is there a better solution? Earlier I've used protocols for state machines which makes it easy, but I'd like to try the functionality of GameplayKit.


Solution

  • You're on the right track. Add the state machine variable in GameScene and initialise its starting state.

    import SpriteKit
    import GameplayKit
    
    class GameScene: SKScene {
        var stateMachine: GKStateMachine!
    
        override func didMove(to view: SKView) {
            self.stateMachine = GKStateMachine(states: [
                StartState(scene: self),
                PlayingState(scene: self),
                PausedState(scene: self),
            GameOverState(scene: self)
            ])
    
            self.stateMachine.enter(StartState.self)
        }
    
        override func update(_ currentTime: TimeInterval) {
            self.stateMachine.update(deltaTime: currentTime)
        }
    }
    

    Then initialise the states so they accept GameScene as input parameter.

    import SpriteKit
    import GameplayKit
    
    class StartState: GKState {
        var scene: GameScene!
    
        init(scene: GameScene){
            super.init()
    
            self.scene = scene
        }
    
        override func isValidNextState(_ stateClass: Swift.AnyClass) -> Bool {
            return stateClass == PlayingState.self
        }
    
        override func updateWithDeltaTime(seconds: TimeInterval) {
            self.stateMachine?.enterState(PlayingState.self)
        }
    }