2
votes

I'm writing a game that has a number of switch sprites that can be moved by the game player.
I was intending to use a 'Game-play-kit' state machine to organize my code.
I can't figure out how to manage multiple state machines - specifically I store my switches in an array, and each switch object includes a statemachine -
how do I reference the 'parent' switch from within GKState classses in order to change it's properties(in this case running a new animation?)

This is my switch class:

class RailSwitch: SKSpriteNode {

var switchID: Int
var currentSwitchPosition: switchPosition
var initialSwitchPosition: switchPosition
var switchLocation: CGPoint
var isSwitchLocked: Bool
var isLeftMiddleSwitch: Bool
var currentAnimation: switchAnimation /* this is a dictionary of animation textures */

var stateMachine : GKStateMachine! 


init(switchID: Int,
     switchLocation: CGPoint,
     initialSwitchPosition: switchPosition,
     isSwitchLocked: Bool,
     isLeftMiddleSwitch: Bool,
     currentAnimation: switchAnimation,
     texture:SKTexture!) {

    self.switchID = switchID
    self.switchLocation = switchLocation
    self.initialSwitchPosition = initialSwitchPosition
    self.currentSwitchPosition = initialSwitchPosition
    self.isSwitchLocked = isSwitchLocked
    self.isLeftMiddleSwitch = isLeftMiddleSwitch
    self.currentAnimation = currentAnimation


    super.init (texture: texture!, color: UIColor.clearColor(), size: texture!.size())

}



required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

This is my switch Network class:

class SwitchNetwork {

var level : Int
var switchNetwork = [RailSwitch]()
var railSwitchAnimation : [switchAnimationState: switchAnimation]

init (level:Int) {
    self.level = level
    self.switchNetwork = []
    self.railSwitchAnimation = [:]
}

func initialiseSwitches() {

    /* one test example switch - in practice there will be many*/

    railSwitchAnimation = loadSwitchAnimations()
    switchNetwork.append(RailSwitch(switchID: 1,
        switchLocation: CGPointMake(400,300),
        initialSwitchPosition: (.left) ,
        isSwitchLocked: false,
        isLeftMiddleSwitch: true,
        currentAnimation: railSwitchAnimation[.left]!,
        texture: railSwitchAnimation[.left]!.textures[0]
        ))
}

I initiate the switches from within GameScene:

func initiateSwitchNetwork() {

    for thisSwitch in 0 ... switches.switchNetwork.count - 1 {

        switches.switchNetwork[thisSwitch].stateMachine = GKStateMachine(states: [
            GameStart(scene: self),
            SwitchLeft(scene: self),
            SwitchRight(scene: self),
            SwitchMiddle(scene: self),
            SwitchLeftLocked(scene: self),
            SwitchRightLocked(scene: self),
            SwitchMiddleLocked(scene: self)])
        switches.switchNetwork[thisSwitch].stateMachine.enterState(GameStart)
    }

Here's my question.
From within the switch statemachine gkstate classes, who do I change the animation?
I need to access the parent switch object that holds the statemachine somehow?

class GameStart: GKState {


    unowned let scene: GameScene

    init(scene: SKScene) {
        self.scene = scene as! GameScene

        super.init()
    }

    override func didEnterWithPreviousState(previousState: GKState?) {
        // scene.addChild(scene.switches.switchNetwork[0].currentAnimation.textures[0])
    }
}
1
I've looked online and every implementation of multiple objects (e.g. multiple enemies etc) make use of the entity-component system in addition to the state machine. Is there a way of avoiding the entity-component system to achieve this - my game is too simple to warrant thatsteve farmer

1 Answers

0
votes

One approach to consider is instead of passing the scene into each state's init function, you could pass a reference to the parent switch instead? So your state's init function looks like this;

init(switch: RailSwitch) {
    self.railSwitch = switch
    super.init()
}

Then your RailSwitch might have a function to change the animation which you would call in the state's updateWithDeltaTime function.

override func updateWithDeltaTime(seconds: NSTimeInterval) {
    self.railSwitch.changeAnimation(to switchTexture: .left)
}

Note that you have access to the stateMachine in each state;

override func updateWithDeltaTime(seconds: NSTimeInterval) {
    self.stateMachine?.enterState(SwitchRight.self)
}

As an aside, I would prefer to use Strategy Pattern to implement this kind of functionality, unless a switches next state is strongly determined by current state. Strategy is better suited where an external factor will determine the next change.