Skip to content

Instantly share code, notes, and snippets.

@vkbsb
Created December 26, 2022 05:36
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vkbsb/e9f323d5654598f260795f5e0d4bbdaa to your computer and use it in GitHub Desktop.
Save vkbsb/e9f323d5654598f260795f5e0d4bbdaa to your computer and use it in GitHub Desktop.
xstate usage in cocos creator 3.6
import { _decorator, Component, Node, input, Input, EventKeyboard, KeyCode } from 'cc';
import { GameStateMachine } from './GameStateMachine';
import { GameEvents } from './GameStates';
import xstate from "xstate/dist/xstate.js"
const interpret = xstate.interpret
const { ccclass, property } = _decorator;
@ccclass('GameHandler')
export class GameHandler extends Component {
@property(Node)
gameScenes:Node[] = []
stateMachine:any
start() {
let context = {
node:this.node,
component: this
}
const sm = GameStateMachine.withContext(context)
this.stateMachine = interpret(sm)
this.stateMachine.start()
input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this)
input.on(Input.EventType.KEY_UP, this.onKeyUp, this)
}
onKeyDown(event: EventKeyboard){
switch(event.keyCode) {
case KeyCode.KEY_A:
console.log('Press a key');
break;
case KeyCode.ENTER:
console.log("Enter Pressed")
this.stateMachine.send({type:GameEvents.UI_NEXT, value:event})
break
}
}
onKeyUp(event: EventKeyboard){
switch(event.keyCode) {
case KeyCode.KEY_A:
console.log('Release a key');
break;
}
}
update(deltaTime: number) {
this.stateMachine.send({type:GameEvents.UPDATE, value:deltaTime})
}
onDestroy () {
input.off(Input.EventType.KEY_DOWN, this.onKeyDown, this);
input.off(Input.EventType.KEY_UP, this.onKeyUp, this);
}
}
import { _decorator, log, Node} from 'cc';
import xstate from "xstate/dist/xstate.js"
const createMachine = xstate.createMachine
import { GameStates, GameEvents, GameStateMainMenu, GameStateGamePlay, GameStateGameOver } from './GameStates';
import { GameHandler } from './GameHandler';
export const GameStateMachine = createMachine({
id: 'gamesm',
initial: GameStates.MAINMENU,
states: {
[GameStates.MAINMENU]: GameStateMainMenu,
[GameStates.GAMEPLAY]: GameStateGamePlay,
[GameStates.GAMEOVER]: GameStateGameOver
}
},{
actions: {
'pendingEntry':(context, event)=>{
log("Event:", event, " Context:", context)
},
'resolvedUpdate': (context, event)=>{
log("resolvedUpdate")
}
}
})
import { GameHandler } from "./GameHandler"
import { _decorator, log, Node } from 'cc';
export const GameStates = {
MAINMENU:'mm',
GAMEPLAY:'gp',
GAMEOVER:'go'
}
export const GameEvents = {
UI_START:'uis',
UI_NEXT:'uin',
UPDATE:'up',
}
export const GameStateMainMenu = {
on:{
[GameEvents.UI_NEXT]:{
actions:(context, event)=>{
log("GameStateMainMenu:ui_next")
},
target:GameStates.GAMEPLAY
}
},
entry:(context, event)=>{
log("GameStateMainMenu:entry")
const gh:GameHandler = context.component
gh.gameScenes[0].active = true
gh.gameScenes[1].active = false
gh.gameScenes[2].active = false
},
exit:(context, event)=>{
log("GameStateMainMenu:exit")
const gh:GameHandler = context.component
gh.gameScenes[0].active = false
}
}
export const GameStateGamePlay = {
on:{
[GameEvents.UI_NEXT]:{
actions:[(context, event)=>{
log("GameStateGamePlay:ui_next")
}],
target:GameStates.GAMEOVER
},
[GameEvents.UPDATE]:{
actions:(context, event)=>{
log("GameStateGamePlay:update")
}
}
},
entry:(context, event)=>{
log("GameStateGamePlay:entry")
const gh:GameHandler = context.component
gh.gameScenes[0].active = false
gh.gameScenes[1].active = true
gh.gameScenes[2].active = false
},
exit:(context, event)=>{
log("GameStateGamePlay:exit")
}
}
export const GameStateGameOver = {
entry:(context, event)=>{
log("GameStateGameOver:entry")
let gh:GameHandler = context.component
gh.gameScenes.forEach((n:Node, index:number, arr:Node[])=>{n.active = false})
gh.gameScenes[2].active = true
},
type: 'final'
}
@vkbsb
Copy link
Author

vkbsb commented Dec 26, 2022

If you are looking for a lightweight version of the state machines, you can use the @xstate/fsm which is 1kb in size but is limited in feature set.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment