从Redux Reducer发出事件

时间:2015-12-07 16:21:29

标签: javascript redux

我在一个简单的射击游戏中使用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(上面描述的reducer也在服务器上运行),用于计算各种统计数据(例如,被摧毁的敌人等)。

Ps:这些“发出的”事件对国家没有影响(它们完全无关),所以我确信它们不应该是行动(因为它们会离开国家)不变)。在reducer完成后处理它们,之后它们可以被删除(reducer总是接收一个空的events数组)。

1 个答案:

答案 0 :(得分:0)

我很确定您可以将其分为三个部分:

-操作:

  const fireWeapon = ()=>({
   type: FIRE_WEAPON
   })

您可以启动fireWeapon okey之类的操作,正如您所说的reducers是纯函数,因此您可以在状态中存储已启动该操作的次数。

-减速器起火

 initialState: { fireWeapon: 0, fireShotgun:0}

 CASE FIRE_WEAPON: 
   return {...state, fireWeapon: state.fireWeapon+1}

最后,关键部分是一个名为redux-observable的库,它基于rxjs和反应式编程。您可以订阅一系列操作并发出新的操作。

一个非常简单的例子是:

export const clearDeletedSiteEpic = (action$,state$) =>
  action$.pipe(
    ofType(FIRE_WEAPON),
    map(() => {
     if (state$.value.fires.fireWeapon % 2 === 0){
       playerDestroyed() // action is launched 
     }
   }
  );