Hola Habr! En esos años no tan lejanos, en el primer año de la facultad de "programadores", me gustaba preguntarles a mis compañeros: "ÂżPor quĂ© fuiste a estudiar aquĂ?" Por supuesto, no mantuve estadĂsticas precisas de las respuestas, pero lo recuerdo con certeza: más de la mitad querĂa hacer juegos. La mayorĂa de los que respondieron de esta manera no estaban preparados para la abundancia de diferentes tipos de "matemáticos" y "fĂsicos" con los que estuvimos llenos en los primeros dos años de estudio. No todos sobrevivieron: al final del segundo año de los cinco grupos superpoblados, habĂa tres incompletos.
No hace mucho tiempo, nuestro equipo de front-end tuvo la oportunidad de probarse en el papel de gamedev. Muy brevemente, la tarea es esta: hacer un juego 3D real, para que puedas jugar con solo abrir el navegador. Incluso mĂłvil. Incluso en webview.

, , , — React + Redux, « », , , .
RnD , : « CodeFest — . — ». , , , . Gods in the sky.

CodeFest .
MMO TPS , , . , , , . CodeFest. , .
2 , , 2 . , , .
: -, — , . , N , — 1 . , — 15 . , , 16-. , , :
- 30 . CodeFest, — , «». , .
- «» . , :
- 90 CPU;
- 120 ;
- 270 /c — , 675 /c — .
- 4,2 /c. , . — UDP WebRTC, . .
- . 2 , , , . , - Node.js , .
, , ( ?), , , , . .
, . , «». — .
:
, , , . , , 5 , , 40 .
-. , , — . React Redux. c 3D-, , Gods in the sky, three.js.
, .
:

, Node.js. :
- , - ( , IE11);
- access-;
- html- .
SSR . kubernetes , . , . , , , , ( ). . Nginx.
. TS, AppState, :
interface AppState {
gameState: GameState;
gameObjects: GameObjects;
data: Data;
requests: RequestsState;
}
requests
— , — . , — . .
data
— , , , , «». .
GameState
:
stage: 'factoids' | 'citySelect' | 'flyShow' | 'game' | 'results';
— . :
elapsedTime: number;
— , , .
, factoids
flyShow
, , — elapsedTime
. 0, . , . , , , . , . … - , .
, , :
interface GameObjects {
user: UserInGame;
gifts: { [id: string]: GiftInGame; };
boosts: { [id: string]: Boost; };
bombs: { [id: string]: Bomb; };
}
, : , , . — .
GameObjects — . , FPS . GPU 100 . Redmi Note 7 40 FPS ( ). MI 5S 30 FPS, 20 , .
, . .
- Redux, — . Redux , . ? Redux, .
, . , . «» ( . behavior — ). , .
. — tick, . , . tick . :
- , , , . , , , .
- ( Redux-), .
, «» . - , gameObjects, . , «», .
25 ( ).
. ( ), React, . - , «- » ( , , ).

. pixabay.com
, FPS- 13. , , - MI 5S, FPS- — 5-6, . .
: performance — , . , , .
FPS=30 , :
- Redux
FPS * ~[ ] ~= 750
, , . - React’
FPS * ~2 * ~[ ]
. - three.js , , WebGL . , .
- (.. 150 ) 4-6 , .. .
- CSS- .
- , FPS 2-4 ( , «» ).
- React.memo, - , .
React :
* ~2
, connect
. connect
— - HOC, , .- , React – (render pass), CPU, GPU.
: React.memo , , «», , DOM-, .
, React + Redux, .
Redux
Redux — . ~1 , . ~1, - — . -, , GameObjects , :
export function setNextGameObjects(payload: GameObjects) {
return {
type: 'SET_NEXT_GAME_OBJECTS' as const,
payload,
};
}
GameObjects :
- , .
SET_NEXT_GAME_OBJECTS
. - , , GameObjects. Redux , - .
SET_NEXT_GAME_OBJECTS
.
:
let state = store.getState().gameObjects;
for (const action of this.collectedActions) {
state = gameObjectsFakeStateReducer(state, action);
}
store.dispatch(setNextGameObjects(state));
collectedActions — , . — , .
— ~25 10 : ~2 . , gameObjectsFakeStateReducer . 25 . , .
? , perf-. 3 :
- ES2018, ~50 < ES2018 (, Firefox — ). , spread.
- Object.assign 300 .
- 500 , « » .
, , , — ES2018, . Firefox.
№3 , … . .
Object.assign. gameObjectsFakeStateReducer
gameObjectsFastStateReducer
, - :
switch (action.type) {
case 'PARTIAL_GIFT_STATE_PATCH':
if (!state.gifts[action.payload.id]) {
return state;
}
Object.assign(state.gifts[action.payload.id], action.payload);
break;
}
? , . , . 25 1 2-4 ( CPU). :

«» , , Redux 10 . , - , , connect gameObjects. , .
React
React . — DOM. , , — reselect, React.memo/React.PureComponent, shouldComponentUpdate . .
, , ~2, — 5. , React , .. DOM .
batch React + Redux. , — . , ?
, , connect . , .
. , <ScoreBoard />
,
- ;
- , .

React.PureComponent, connect mapStateToProps. elapsedTime
score
. Score
, elapsedTime
— . elapsedTime
- render. , FPS, shouldComponentUpdate. HOC’a connect — shouldComponentUpdate .
, «» , :
- shouldComponentUpdate,
elapsedTime
( ). , HOC’a connect. - mapStateToProps . , , . connect’a.
- useSelector. , .. . , , , .
- — connect, — . , . ScoreBoard .
— ! ScoreBoard’a connect, , . mapStateToProps , .
, connect. , — - - canvas-, three.js (, , .). render , :
return <div id="map" className={s.map} ref={mapRef} />;
return <canvas id="scene" className={s.scene} ref={sceneRef} />;
, DOM — . , React . , componentDidUpdate, . , componentDidUpdate :
public componentDidUpdate() {
const { geoPos, orientedRotationQuanternion } = this.props;
const { map } = this.state;
map.setQuat(orientedRotationQuanternion);
map.setCenter([geoPos[0], geoPos[1]], { animate: false });
map.setZoom(getMapZoomFromHeight(geoPos[2]), { animate: false });
}
, componentDidUpdate . :
- connect. , mapStateToProps;
public shouldComponentUpdate() { return false; }
— «» «»;- Redux ( ) useStore ;
- (
store.subscribe(() => { /* … */})
); - ;
- !
:
store.subscribe(() => {
const state = store.getState();
const { map } = this.state;
const { geoPos, orientedRotationQuanternion } = state.gameObjects.user;
map.setQuat(orientedRotationQuanternion);
map.setCenter([geoPos[0], geoPos[1]], { animate: false });
map.setZoom(getMapZoomFromHeight(geoPos[2]), { animate: false });
});
, , .
, - , .

. — React Tree Reconcilation + Commit

React Tree Reconcilation + Commit
React + Redux , :
- , , , «» React , ;
- ;
- « », , ;
- , .
, . , . , . ? .
:
- , , , , . , .
- , React’ 30 . : .
- , .
- . . , .
- .
- Performance — . CPU — , Intel i9.
- - : 12–20 – . , .
- , . , , . , .
- , , . IE11 , . 70- Edge 18- ( ).
- WebGL . - , , -, Firefox linux, . . — . -, . , , « », .
, :
- Firefox. . , WebGL, — spread. FPS Firefox , Chrome. , , .
- IPhone. Safari IE6 220 . , , . , , . . — - .
- . . . , , (, , ). .
- . , , . , , , «» .
- ( ), – , . .
, , . iOS, Android Web .