Emitting Events from Redux Reducers

I use redux as a state container in a simple shooter game. The state is completely determinate, the only input that the system receives is user input (for example, a weapon has been fired, etc.). My problem is that I have to track (and process) certain events that occur during the game (for example, something was destroyed, etc.), and I'm not quite sure how to do this. My real solution is that the reducer maintains the events array in its current state, and each reducer simply adds events to it.

 FIRE_WEAPON+-+ FIRE_WEAPON+-+ | | | | +-v--------+--------------v-------------> | | +->PLAYER_DESTROYED 

Two FIRE_WEAPON actions get abbreviations FIRE_WEAPON and should "emit" the PLAYER_DESTROYED event (right now it is used to render there).

The project is open source, the gearbox looks something like this (it's just pseudo-code, but here is the corresponding 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), }; } 

We can assume that handleUserInput is a simple identity function x => x (it does not apply to the events array). During evolve I would like to β€œemit” events, but since this would make evolve unclean, I cannot do this. As I said, now I am doing this, keeping the events that have happened in a state, but there may be a better way. Any suggestions?

These events are used during rendering, which looks like this:

 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); } 

But later, I would like to use events on the server (the reducer described above also runs on the server) to calculate various characteristics (for example, destroyed enemies, etc.).

Ps: these "emitted" events do not affect the state (they are completely unrelated), so I am sure that they should not be actions (because they will leave the state unchanged). They are processed after the reducer completes, after which they can be discarded (the reducer always receives an empty events array).

+5
source share
1 answer

I am sure you can divide it into three parts:

-Actions:

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

You can run actions like fireWeapon okey, because you said that reducers are pure functions, so you can keep in the state how many times you run this action.

-Reducer Fires

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

And finally, the key part, a library called redux-observable, is based on rxjs, reactive programming. You can subscribe to the action flow and release new ones.

A really simple example:

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

Source: https://habr.com/ru/post/1237586/


All Articles