Last active
July 24, 2019 02:31
-
-
Save SupremeTechnopriest/b5bd84d04f12d80b07e21d118d725556 to your computer and use it in GitHub Desktop.
Finite State Game Mode Script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
properties: | |
scripts: | |
- /game-modes/sandbox/fsm.js | |
- /game-modes/sandbox/start.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import StateMachine from 'javascript-state-machine' | |
export default function (props) { | |
this.on('start', start.bind(this, props)) | |
} | |
function start (props) { | |
this.fsmManager = new FSMManager(this.engine) | |
} | |
class FSMManager { | |
constructor (engine) { | |
this.engine = engine | |
this.entities = {} | |
} | |
addFSM (entity, data) { | |
// Create an entry for this client if it doesnt exist | |
if (!this.entities[entity.nid]) this.entities[entity.nid] = {} | |
// Create the method | |
const methods = {} | |
Object.keys(data.methods).forEach(method => { | |
methods[method] = (...args) => { | |
let { op, component, defaults, values } = data.methods[method] | |
if (values) defaults = values | |
if (!defaults) defaults = {} | |
// Process automated operations | |
switch (op) { | |
case 'add': | |
this.engine.addComponent(entity, component, defaults) | |
break | |
case 'remove': | |
this.engine.removeComponent(entity, component) | |
break | |
case 'update': | |
if (this.engine.getComponent(entity, component)) { | |
this.engine.updateComponent(entity, component, defaults) | |
} | |
break | |
default: | |
// NoOp | |
} | |
// Fire an event for scripts to consume | |
this.engine.emit(method, entity, ...args) | |
} | |
}) | |
// Create the fsm | |
const fsm = new StateMachine({ | |
init: data.init, | |
transitions: data.transitions, | |
methods | |
}) | |
// Add a record for this entity | |
if (data.name) { | |
this.entities[entity.nid][data.name] = fsm | |
} else { | |
this.entities[entity.nid] = fsm | |
} | |
} | |
setState (entity, name, state, props = []) { | |
const fsm = name ? this.fsms[entity.nid][name] : this.fsms[entity.nid] | |
if (fsm.can(state)) fsm[state](...props) | |
} | |
removeFSM (entity, name) { | |
if (name) { | |
delete this.entities[entity.nid][name] | |
} else { | |
delete this.entities[entity.nid] | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Player | |
components: | |
- POSITION | |
- ROTATION | |
fsm: | |
init: idle | |
transitions: | |
- | |
name: emote | |
from: idle | |
to: emoting | |
methods: | |
onEmote: | |
- | |
op: add | |
component: EMOTE | |
defaults: | |
emote: wave |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// The this scope of .scripts and .systems is the modngn instance | |
export default function (props) { | |
this.on('update', update.bind(this)) | |
this.on('client-connected', onConnect.bind(this, props)) | |
this.on('client-disconnected', onDisconnect.bind(this)) | |
this.on('onEmote', (entity, emote) => { // do stuff with emote }) | |
} | |
function onConnect (props, { client, clientData, callback }) { | |
// Create a player body for this client. | |
const entity = this.entities.Player() | |
// Add fsm to player | |
const fsm = this.getAddress('player.body.entity.fsm') | |
this.fsmManager.addFSM(entity, fsm) | |
this.fsmManager.setState(entity, 'emote', 'wave') | |
// Establish a relation between entity and client. | |
entity.client = client | |
client.entity = entity | |
// Define the view. This area of the game visible to | |
// this client. All else is culled. | |
client.view = { | |
x: entity.x, | |
y: entity.y, | |
halfWidth: 1000, | |
halfHeight: 1000 | |
} | |
// Send the call back | |
callback({ accepted: true, text: 'Welcome!' }) // eslint-disable-line | |
} | |
function onDisconnect ({ client }) { | |
this.fsmManager.removeSpine(client.entity) | |
this.engine.removeEntity(client.entity) | |
} | |
function update ({ delta, tick, now }) { | |
// Set each clients view | |
this.engine.instance.clients.forEach(client => { | |
client.view.x = client.entity.x | |
client.view.y = client.entity.y | |
}) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment