这就是我最终做的......
const state = {
_data:{}, // object in which the data is actually stored
get:(path) => { // safely get the value or return undefined
return path.split('.').reduce((o,i)=>(o||{})[i], state._data)
},
set:(fullpath,value,silent=0) => { // safely set the value
function cycle(obj,path,value) {
let i = path[0]
if(path.length==1) { // if this is the end of the path
obj[i] = value; // change the value
if(!silent) { Pubsub.publish('state.'+fullpath, value) ; } // and publish the event
} else { // if this is not the end of the the path
if(typeof obj[i] !== 'object') { obj[i] = {} } // create this part of the path if it doesn't exist
cycle(obj[i],path.slice(1), value) // move on to the next part of the path
}
}
cycle(state._data,fullpath.split('.'),value)
}
第 1 步:获取和设置
我创建了两个自定义函数来获取和设置状态。
get() 将点符号路径作为字符串,例如state.get('buildings.bakery.unlocked')
.
set() 还将点符号路径作为字符串以及值,例如state.set('buildings.bakery.unlocked', 1)
.
我使用了这个线程的一些代码。使用这些函数意味着可以轻松操作嵌套属性,而不必担心可怕的 TypeError。
第 2 步:发布订阅
点符号路径还提供了发布/订阅模型。我正在使用PubSubJS。调用 set() 还会发布与路径匹配的事件,例如state.set('abilities.strength', 5)
也发布'state.abilities.strength'
。
要监控状态变化,您只需订阅相关事件:
PubSub.subscribe('state.abilities.strength', () => console.log('strength value changed'))
发布的事件也会传回新的值,所以你可以用它做你想做的事:
PubSub.subscribe('state.inventory.bread', (path, value) => console.log('bread value changed, you now have ' + value))
第 3 步:实施以进行比较
PubSub 具有作为基于主题的系统的好处。这意味着您可以订阅非最终节点:
PubSub.subscribe('state.inventory', () => console.log('something in the inventory changed'))
PubSub.subscribe('state.inventory.water', () => console.log('water changed'))
改变inventory.bread
会触发第一个,改变inventory.water
会触发两者。
这使我可以将游戏逻辑与状态分开。有两种比较值的方法...
// function to compare two values
let comparison = function () {
console.log('running comparison');
if(state.get('test.valueA') > state.get('test.valueB')) {
console.log('A is bigger than B');
}
}
// you either subscribe to both the values, and compare whenever either one changes
PubSub.subscribe('state.test.valueA', comparison)
PubSub.subscribe('state.test.valueB', comparison)
// or alternatively, if they have a shared topic, then subscribe to that
PubSub.subscribe('state.test', comparison)