OlĂĄ Habr! Naqueles anos nĂŁo tĂŁo distantes, no primeiro ano do corpo docente "programador", eu gostava de fazer aos colegas a pergunta: "Por que vocĂȘ veio aqui para estudar?" Obviamente, nĂŁo mantive estatĂsticas precisas das respostas, mas lembro-me com certeza: mais da metade queria fazer jogos. A maioria dos que responderam dessa maneira nĂŁo estava preparada para a abundĂąncia de diferentes tipos de "matemĂĄticos" e "fĂsicos", com os quais fomos surpreendidos nos dois primeiros anos de estudo. Nem todos sobreviveram - atĂ© o final do segundo ano dos cinco grupos superlotados, havia trĂȘs incompletos.
HĂĄ nĂŁo muito tempo atrĂĄs, nossa equipe de front-end teve a oportunidade de tentar o papel de gamedev. Muito brevemente, a tarefa Ă© a seguinte: criar um jogo 3D real, para que vocĂȘ possa jogar apenas abrindo o navegador. Mesmo mĂłvel. Mesmo na visualização na web.

, , , â 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 .