Let’s create a StateMachine class that controls the behaviour (BaseState) of GameObject. Each GameObject should have at least one state machine. You can use 3 buttons to change the behaviour of a game object. For now, just create one object to test your StateMachine class.
Note that there are multiple files here.
BaseState.h
@class StateMachine
@interface BaseState : NSObject {
NSString *myName; //name of state
StateMachine *mySM; //the state machine this state belongs to
}
@property(nonatomic, readonly) NSString *myName;
@property(nonatomic, readonly) StateMachine *mySM;
- (id)initWithName:(NSString *)name stateMachine:(StateMachine *)sm;
- (void)enter;
- (void)update:(float)dt;
- (void)exit;
@end
BaseState.m
#include “StateMachine.h”
@implementation
@synthesize myName, mySM;
- (id)initWithName:(NSString *)name stateMachine:(StateMachine *)sm {
if((self = [super init])) {
myName = name;
mySM = sm;
[mySM addState:self];
}
return self;
}
- (void)enter {
}
- (void)update:(float)dt {
}
- (void)exit {
}
@end
StateMachine.h
#include “BaseState.h”
@class GameObject
@interface StateMachine : NSObject {
BaseState *currState; //current state that is running
BaseState *nextState; //the next state to run
NSMutableDictionary *stateList; //to store all states
GameObject *myGO; //the game object this state machine belongs to
}
@property(nonatomic, readonly) GameObject *myGO;
- (id)initWithGO:(GameObject *)go;
- (void)addState:(BaseState *)state;
- (void)setInitialState:(NSString *)name;
- (void)setNextState:(NSString *)name;
- (void)enter;
- (void)update:(float)dt;
- (void)exit;
@end
StateMachine.m
@implementation
@synthesize myGO;
- (id)initWithGO:(GameObject *)go {
if((self = [super init])) {
myGO = go;
stateList = [[NSMutableDictionary alloc] initWithCapacity:1];
}
return self;
}
- (void)dealloc {
[stateList release]; //anything we alloc in this file, we must release ourselves. In general, no alloc = no release
[super dealloc];
}
- (void)addState:(BaseState *)state {
[stateList setObject:state forKey:state.myName];
if(currState == nil)
currState = nextState = state;
}
- (void)setInitialState:(NSString *)name {
BaseState *state = [stateList objectForKey:name];
if(state != nil) {
currState = nextState = state;
}
}
- (void)setNextState:(NSString *)name {
BaseState *state = [stateList objectForKey:name];
if(state != nil) {
nextState = state;
}
- (void)enter {
[currState enter];
}
- (void)update:(float)dt {
if(nextState != currState) {
[currState exit];
currState = nextState;
[currState enter];
}
[currState update:dt];
}
- (void)exit {
[currState exit];
}
@end
LeftRightState.h
@interface LeftRightState : BaseState {
}
@end
LeftRightState.m
@implementation
- (void)update:(float)dt {
static float timer = 0;
static float vel = 50;
timer += dt;
if(timer >= 1.0) {
timer -= 1.0;
vel = -vel;
}
self.mySM.myGO.position = vel * dt;
}
@end
RoundAboutState.h
@interface RoundAboutState : BaseState {
CGPoint centerP; //RounAboutState specific member variable
}
@end
RoundAboutState.m
@implementation
- (void)enter {
centerP = ccp(self.mySM.myGO.position.x – 50, self.mySM.myGO.position.y);
}
- (void)update:(float)dt {
static float timer = 0;
static float vel = 50;
timer += dt;
self.mySM.myGO.position = ccp(centerP.x + 50 * cos(timer), centerP.y + 50 * sin(timer));
}
@end
GameScene.m
@include “GameData.h”
…
- (void)init {
//your scene initialization
…
//GameObject initialization
go = [[GameObject alloc] init…]; //declared in GameScene.h
StateMachine *sm = [[StateMachine alloc] initWithGO:go];
BaseState *state = [[LeftRightState alloc] initWithName:@”leftright” stateMachine:sm];
state = [[RoundAboutState alloc] initWithName:@”roundabout” stateMachine:sm];
…
//create 3 buttons with doSomethingOne/Two/Three
…
}
- (void)doSomethingOne {
[go.sm setNextState:@"leftright"];
}
- (void)doSomethingTwo {
[go.sm setNextState:@"roundabout"];
}
- (void)doSomethingThree {
[go.sm setNextState:@"_your_own_state"];
}
- (void)update:(float)dt {
[go.sm update];
}
…
//remember to dealloc your go, sm and states!
@end