State machines are easy. If you want an overview, I’ll defer (again) to Game Programming Patterns.

The full source code for this series of posts is up as JLFGameplayKit on GitHub. The code for this particular post is tagged as part2-state-machines.

The GKState interface is really straightforward:

@interface GKState : NSObject

+ (instancetype)state;

@property (nonatomic, readonly, weak) GKStateMachine *stateMachine;

- (BOOL)isValidNextState:(Class)stateClass;
- (void)didEnterWithPreviousState:(GKState *)previousState;
- (void)willExitWithNextState:(GKState *)nextState;
- (void)updateWithDeltaTime:(CFTimeInterval)seconds;

@end

Apple went again with Class instances as identifiers for states, as it did with components. There’s nothing really tricky in there, except that -isValidNextState: appears to return YES by default, which feels weird to me:

Testing GKState in a playground on El Capitan

I’d have gone with NO. I did, actually, and had to change it after I got around to double-checking. :)

GKStateMachine is also straightforward:

@interface GKStateMachine : NSObject

+ (instancetype)stateMachineWithStates:(NSArray *)states;
- (instancetype)initWithStates:(NSArray *)states;

@property (nonatomic, readonly) GKState *currentState;

- (BOOL)canEnterState:(Class)stateClass;
- (BOOL)enterState:(Class)stateClass;
- (GKState *)stateForClass:(Class)stateClass;
- (void)updateWithDeltaTime:(CFTimeInterval)seconds;

@end

Same deal as last time, we can implement this by storing the states in a NSMapTable.

The only interesting bit in this is making sure there’s only one kind of each state type in there, and you can do that by just making sure there’s not an existing value in your map table as you add states to it.

For the demo, I re-implemented the Wander component from last time using a state machine, and added an extra action in there on the sprite that supports it. The state diagram for wandering looks like this:

Wander state diagram

JFLGameplayKit on GitHub