【发布时间】:2015-12-07 16:21:28
【问题描述】:
我在一个简单的射击游戏中使用redux 作为状态容器。状态是完全确定的,系统接收的唯一输入是用户输入(例如,武器被开火等)。
我的问题是我必须跟踪(和处理)在游戏期间发生的某些事件(例如,某些东西被破坏等),我不太确定如何做到这一点。
我目前的解决方案是reducer在当前状态下维护一个events数组,每个reducer只是追加事件。
FIRE_WEAPON+-+ FIRE_WEAPON+-+
| |
| |
+-v--------+--------------v------------->
|
|
+->PLAYER_DESTROYED
这里reduce 接收两个FIRE_WEAPON 动作,并且应该“发射”一个PLAYER_DESTROYED 事件(现在,它用于在那里渲染爆炸)。
project 是开源的,reducer 看起来像这样(这只是伪代码,但这里是relevant game logic):
// combine is just (f, g) => ((s, a) => g(f(s, a), a))
const reducer = combine(
// simulate world
(state, action) => {
while (state.time < action.time) {
state = evolve(state, delta); // evolve appends the happened in-game events to the state
}
return state;
},
// handle actual user input
(state, action) => {
return handleUserInput(state, action);
}
);
const evolve = (state, delta) => {
const events = [];
// some game logic that does some `events.push(...)`
return {
...state,
time: state.time + delta,
events: state.events.concat(events),
};
}
我们可以假设,handleUserInput 是一个简单的x => x 标识函数(它不涉及events 数组)。
在evolve 期间,我想“发出” 事件,但由于这会使evolve 不纯,我不能这样做。
正如我所说,现在我通过将发生的事件存储在状态中来做到这一点,但可能有更好的方法。有什么建议吗?
这些events在渲染过程中使用,看起来像这样:
let sprites = [];
// `subscribe`d to store
function onStateChange() {
// `obsolete` removes old sprites that should not be displayed anymore
// `toSprite` converts events to sprites, you can assume that they are just simple objects
sprites = sprites.filter(obsolete).concat(store.getState().events.map(toSprite));
}
function render(state) {
renderState(state);
renderSprites(sprites);
}
但稍后我想在服务器上使用events(上面描述的减速器也在服务器上运行),用于计算各种统计数据(例如,被摧毁的敌人等)。
Ps.:这些 "emitted" 事件对状态没有影响(它们完全不相关),所以我确信它们不应该是动作(因为它们会离开状态不变)。它们在 reducer 完成后被处理,之后它们可以被删除(reducer 总是收到一个空的events 数组)。
【问题讨论】:
-
您能否添加一些关于如何使用
events以及它们何时不再有用的信息?你不想永远积累它们。 -
@DanAbramov 帖子已更新!
-
恐怕我还没有足够的上下文。你能展示一下
combine是什么,handleUserInput的样子,最重要的是,实际使用state.events的代码在哪里。 -
@DanAbramov 我希望现在更清楚
-
如果
events总是可以从当前的state计算出来并且不需要存储,似乎你应该在reducers 外部计算它们。例如,请参阅github.com/rackt/redux/blob/master/docs/recipes/…。这有帮助吗?
标签: javascript redux