Skip to content

Instantly share code, notes, and snippets.

@screeny05
Last active March 8, 2018 14:40
Show Gist options
  • Save screeny05/dfab38323a5d3393642ed07209273be0 to your computer and use it in GitHub Desktop.
Save screeny05/dfab38323a5d3393642ed07209273be0 to your computer and use it in GitHub Desktop.
abstract class State<T> {
abstract id: T;
isCurrent: boolean = false;
listeners: { [key: string]: Function } = {};
fsm!: StateMachine<T>;
on(event: string, cb: Function): void {
this.listeners[event] = cb;
}
trigger(event: string, data?: any): void {
if (!this.listeners.hasOwnProperty(event)) {
return;
}
this.listeners[event](data);
}
}
class StateMachine<T> {
possibleStates: State<T>[];
currentState?: State<T>;
constructor(states: State<T>[], initialState: T) {
this.possibleStates = states;
this.transitionToState(initialState);
}
findState(stateId: T): State<T> {
const state = this.possibleStates.find(state => state.id === stateId);
if (!state) {
throw new Error(`StateMachine: State ${stateId} is not available`);
}
return state;
}
transitionToState(nextStateId: T) {
let nextState = this.findState(nextStateId);
let previousState = this.currentState;
if (this.currentState) {
this.currentState.isCurrent = false;
this.currentState.trigger('leave', nextState);
}
this.currentState = nextState;
this.currentState.isCurrent = true;
this.currentState.trigger('enter', previousState);
}
trigger(event: string, data?: any) {
if (!this.currentState) {
return;
}
this.currentState.trigger(event, data);
}
}
enum HeroMovementState {
IDLE,
JUMPING,
MOVING
}
class HeroMovementStateIdle extends State<HeroMovementState> {
id = HeroMovementState.IDLE;
constructor(private hero: Hero) {
super();
this.on('enter', () => this.hero.setGraphics('idle'));
this.on('input', this.onInput.bind(this));
}
onInput(input: any) {
if (input === 20) {
this.fsm.transitionToState(HeroMovementState.JUMPING);
}
}
}
class HeroMovementStateJumping extends State<HeroMovementState> {
id = HeroMovementState.JUMPING;
constructor(private hero: Hero) {
super();
this.on('enter', () => this.hero.setGraphics('jumping'));
}
}
class Hero {
movementState: StateMachine<HeroMovementState>;
constructor() {
this.movementState = new StateMachine<HeroMovementState>([
new HeroMovementStateIdle(this),
new HeroMovementStateJumping(this)
], HeroMovementState.IDLE);
}
setGraphics(graphics: string) { }
update(delta: number) {
this.movementState.trigger('update', delta);
this.movementState.transitionToState(HeroMovementState.IDLE)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment