I’ve recently been experimenting more heavily w/ redux+react, clojurescript + reframe, and vuex+vuejs. I’ve been trying to mix it with games at layer deeper than the ui. For people who like the SSOT/store/immutability I think an interesting place to mix in a game is right at the store. I’m only at the start of this project but here’s some of the prototype code…
The trick was how to make the store pattern relevant to a game – the unidirectional flow of data in those frameworks typically results in some sort of reactive dom rendering (but doesn’t have to).
The stores in all of these things are basically subscribe(mutation, state)
and commit('someMutation', someValue)
which is already about as safe and decoupled as the event stuff I had suggested above. I’ve tried directly tapping into this in reframe and vuex outside of the usual use case.
Vuex - using the store and changing something webgl-ish in babylon:
const state = {
forwards: 87,
backwards: 83,
fov: 0.8,
etc: '...',
}
const getters = { ... }
const actions = {
openKeybindModal(...),
handleKeybindInput(...),
changeFov({ commit }, newFov) {
commit('updateFov', newFov)
}
}
const mutations = {
...
updateFov(state, payload) {
state.fov = payload
}
}
I’ll skip the html parts but there is a ui where the fov can be changed, and saved to local storage and reloaded etc etc – and all of that works the typical web programming way. And now here’s how it plugs in to the game:
// game plugin
store.subscribe((mutation, state) => {
console.log(mutation) // { type: "settings/misc", payload: { fov: 0.8 }
if (mutation.type === 'settings/misc') {
if(mutation.payload.fov) {
camera.fov = mutation.payload.fov
}
}
})
So there we have a store mutation where the reactivity A) updates the settings menu + localstorage, and B) changes the camera fov which is essentially reactivity all the way over in webgl land. The parsing of mutations is a bit tedious (usually automagic in those frameworks).
And here it is going in the opposite direction (game => store) with the added complexity of the game getting its own state from a server (multiplayer, websocket):
networkStuff.messages.forEach(message => {
if (message.protocol.name === 'Scores') {
// format - message.scores: [ { playerId: 123, kills: 5, deaths: 2 }, etc ]
store.commit('game-ui/leaderboard', { scores: message.scores })
// -> causes the k/d and score table to change, which is html for me
// but could also have been babylon-gui via the above pattern
}
})
I’m refactoring a game to get a good portion of its state into a store to see how it goes. Hopefully the experiment works. There’s a lot of game-related state that I would never try to treat immutably… but at least so far a lot of the annoying code (keybinds, in-game ui, player equipment loadout, error modals, chat ui) is coming out better in the flux pattern.