Redux что это в играх
Перейти к содержимому

Redux что это в играх

  • автор:

Что нового: Metro Redux (переиздание)

metro_2033_redux

metro_2033_redux

Недавно в продажу поступили две улучшенные версии легендарной постапокалиптической стрелялки «Метро». Данные игры получили приписку «Redux» и доступны для покупки в steam. Подробности нововведений в статье.

Сразу хочу сказать, что все изменения носят косметических характер и никаких новых сюжетных веток, дополнений по уровням, моделям, дизайну и пр., нет. Это просто техническое (графическое) переоснащение популярной игры, правда с небольшими и геймплейными изменениями.

Metro Redux — это переиздание игры, где обе части переодели в новый (современный) движок. Пишу я это потому, что в сети стали появляться «вбросы», мол в Redux есть новые уровни, концовки и прочее. Так вот, не верьте — всё это враки.

metro_last_light_img

«Что нового в Metro Redux?»

Основные нововведения в Метро 2033:

  • Новый движок — 4A Engine, графон считай подтянули на новый уровень.
  • Улучшена проработка игры — стали лучше тени, прорисовка персонажей, оружия, окружения и текстур.
  • Подправлен баланс — доработан бой ИИ, улучшено управление и его отзывчивость, поправлен стелс режим (наконец-то!), появились мульки из «ласт лайт» (протирание стекла, апгрейд пушек и т.п.).
  • Режим рейнджер

Основные нововведения в Метро Луч надежды:

  • Новый движок — такой же симпотный движок, как и у первой части. В целом, «ласт лайт» стала лучше выглядеть.
  • Возможность выбрать стиль игры — появилась возможность выбрать способ прохождения игры. Всего два режима: «выживание» и «шутер». В выживании будет мало патронов, в приоритете стелс и экономия. Шутер будет полной противоположностью выживанию — будет море стрельбы и экшена.
  • Работа с деталями — появились команды проверки часов и инвентаря.

По сути, это одно большое, самостоятельное обновление (если так можно сказать) и каждый фанат игры сам должен для себя решить — покупать его или нет. В интернетах мнения по этому поводу разделились поровну. Кто-то матерится и посылает все возможные проклятья на разработчиков, за явную попытку дособрать не собранное бабло с фанатов серии, называя redux — платным «патчем», а кто-то искренне радуется нововведениям и играет в обновленные игры с удовольствием.

Моё мнение по этому поводу однозначно — никакие улучшения и заплатки не стоят тех денег, что просят разработчики. Если ещё Метро 2033 по понятным причинам можно «переобуть», она уже давно вышла, то Луч надежды и без фиксов выглядел изумительно. Брать за это деньги, да ещё не малые, я считаю как минимум некрасиво. Печально всё это господа, возможно позже накидаю статейку по этому поводу, а пока вот демка, наглядно показывающая изменения в игре.

Запись опубликована 31.08.2014 автором igra-San в рубрике Новости с метками 2014.

Что нового: Metro Redux (переиздание) : 18 комментариев

  1. Maestro 01.09.2014 в 10:31 Сама по себе игра изначально не плоха, но вообще не понял данного шага разработчиков, особенно когда в Стиме увидел ее новую стоимость.
  1. Лайфхак 03.09.2014 в 15:29 Ды цена конеш адовая, но всем у кого уже есть две игры скидка в 50% даётся вроде как.

Разработчики Metro: Redux поделились подробностями повышения качества графики своих игр

Василий Жужиков 10 августа 2014 в 13:25 23506

Metro: Redux Metro: Redux

Новый движок студии 4A Games будет поддерживать глобальное освещение, тесселяцию местности и множество новых систем, существенно увеличивающих качество графики. Как стало известно , обновленные версии игр Metro 2033 и Metro: Last Light в издании Metro: Redux будут выглядеть намного лучше оригинальных игр, благодаря их портированию на новый движок «Почти вся команда из 80 человек в 4A Games работала над Metro: Redux на протяжении года. Для студии это был очень важный проект с тремя ключевыми элементами: — Мы существенно обновили движок 4A Engine, добавив глобальное освещение и тесселяцию местности, а также множество других функций — Мы портировали Metro: Last Light на новый движок, добавляя несколько новых функций, включая новый стиль игры Survival — Мы полностью перестроили Metro 2033 для работы на движке 4A Engine, с новым усовершенствованным фреймворком Last Light, новым контентом и игровыми элементами», — отметили разработчики в обращении к геймерам. Релиз Metro: Redux состоится 29 августа на новых консолях и РС — напоминает . 185.245.84.218

Читать подробнее на нашем сайте о: Metro: Redux | Metro 2033 | Metro: Last Light

3D-аркада в браузере: как мы сделали игру на React + Redux

Привет, Хабр! В не такие уж далёкие годы, на первом курсе «программистского» факультета, мне нравилось задавать товарищам по учёбе вопрос: «Зачем вы вообще пошли сюда учиться?» Точной статистики ответов я, конечно, не вёл, но доподлинно помню: больше половины хотели делать игры. Большинство тех, кто так отвечал, оказались не готовы к обилию разных видов «математик» и «физик», которыми нас завалили в первые два года учёбы. Выдерживали не все — уже к концу второго курса из пяти переполненных групп осталось три неполных.

Не так давно нашей фронтенд-команде предоставилась возможность попробовать себя в роли gamedev. Очень коротко, задача такая: сделать самую настоящую 3D-игру, да так, чтобы можно было поиграть, просто открыв браузер. Даже мобильный. Даже в WebView.

В этом посте я постараюсь рассказать о том, как мы спроектировали архитектуру игры, с какими проблемами столкнулись, используя один из самых популярных и актуальных технологических стеков — React + Redux, и какими «хорошими практиками», вероятнее всего, придётся пожертвовать, если вы для схожих задач выберете этот же стек.

Как всё начиналось

Год назад на корпоративном портале в разделе для RnD появился зазывающий пост, который начинался такими словами: «Делать стенд на CodeFest — наша добрая традиция. Сделать лучший стенд — наша в меру амбициозная цель». Далее следовал призыв погенерить идеи, ну и, конечно же, реализовать их. Итогом совместного брейншторма и последующих вечерних посиделок стала игра с гордым именем Gods in the sky.

Фото из группы CodeFest в ВК / https://vk.com/codefest. Исходник фото тут.

Фото из группы CodeFest в ВК.

Игру задумали как M MO TPS на авиационную тематику, где каждый игрок управлял собственным самолётом, беспощадно сражался в небе с соперниками и попутно набирал баллы. Из баллов, конечно же, формировалась турнирная таблица, а сами сражения комментировал самый настоящий стример. Игра вполне зашла на CodeFest. Как нам кажется, людям наш стенд понравился.

Как всё продолжалось

Несколько лет подряд 2ГИС готовит к Новому году спецпроекты, которые либо знакомят пользователей с нашим функционалом, либо просто напоминают о 2ГИС как о тёплой и ламповой компании. Часть миссии нашей команды как раз в том, чтобы создавать такие проекты, а потому первичный бриф упал на проработку к нам в начале октября.

Если коротко: самолёты меняем на Санта-Клаусов, пули — на снежки, которые не убивают. А да, ещё в эту игру поиграет N сотен тысяч человек, а дедлайн — 1 декабря. Ну, край — 15 декабря. А, это воскресенье, так что 16-е. Если не вдаваться в детали, то задача кажется очень простой, однако очень быстро всплыли большие но:

  1. Нагрузка на сеть в исходной архитектуре позволяла с комфортом играть не более 30 игрокам одновременно. Этого хватало для CodeFest, но было недостаточно для наших реалий — десятки тысяч игроков в сутки, пусть и в разных «комнатах». Получается, надо перепиливать.
  2. «Железные» ресурсы. Примерная оценка показала, что нам нужно для наших бэкендов:
    • 90 ядер CPU;
    • 120ГБ ОЗУ;
    • 270 Мбит/c — ширина канала на отправку, 675 Мбит/c — на получение в наших ДЦ.
  3. Даже после всех оптимизаций скорость интернета у пользователей должна была быть не меньше 4,2 Мбит/c. Это не так много, но есть далеко не у всех. И цена этого — использовать UDP при помощи WebRTC, а это поддерживается далеко не всеми браузерами. Да и технология нами совсем не изучена.
  4. Делать бэкенд с ресурсами из п. 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

Ветка requests — это самый обычный объект, каждый ключ которого — строка. Он однозначно идентифицирует запросы, значение — его состояние. Неинтересно.

Ветка data — это данные, которые в основном запрашиваются один раз на старте игры, например, список регионов, что доступны для «полетать». Тоже неинтересно.

В GameState есть два интересующих нас поля:

  1. stage: ‘factoids’ | ‘citySelect’ | ‘flyShow’ | ‘game’ | ‘results’; — стадия игры. В нашем случае стадии такие:
    • показ короткой справки;
    • выбор города;
    • облёт сцены;
    • фаза игры;
    • экран результатов.

  2. 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

Ещё один участник команды в тот день. Фото взято с 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 на две части:

  1. Первая обрабатывает только те экшены, которые летят редко или очень редко. Здесь же экшен SET_NEXT_GAME_OBJECTS .
  2. Все те экшены, которые наши бихевиоры выбрасывали, часто переезжают в отдельный редьюсер этой же ветки 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 вывода:

  1. Если переехать на компиляцию с таргетом ES2018, то в Хроме получим прирост скорости работы редьюсеров в ~50 раз относительно компиляции с таргетом < ES2018 (правда, не в Firefox — тот прироста не даёт). Это связано с тем, как работает оператор spread.
  2. Переход на мутабельный стейт с использованием Object.assign даёт прирост производительности операций над ним примерно в 300 раз.
  3. Переход на мутабельный стейт даёт прирост производительности операций над ним примерно в 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; // case, default . >

Плохо? Конечно, кто б спорил. Но работает, и переделка заняла пару часов. Итого переделка одной ветки стейта на антипаттерн даёт нам обработку 25 экшенов за 1 тик за 2-4мс (причем при четырёхкратном замедлении CPU). Пруф из профайлера:

image

Скринов с профайлингом «старой» версии не осталось, поэтому придётся поверить, что совокупная оптимизация Redux дала прирост к производительности всего проекта раз в 10 на этапе формирования нового стейта после каждого тика. Конечно же, из-за появившихся мутаций стейта, пришлось подшаманить некоторые компоненты, которые через connect были подписаны на ту или иную смену ветки стейта gameObjects. Но это мелочи, хоть и не очень приятные.

Про React

Вообще про оптимизации React написано уже очень много статей. Основной их посыл — свести к минимуму изменения DOM. По факту это означает, что нам следует стремиться к минимизации согласований, а делать это можно разными способами — reselect, React.memo/React.PureComponent, вручную написать shouldComponentUpdate и прочее. От минимизации количества согласований и оттолкнёмся.

Мы уже поработали с количеством экшенов, которые мы бросаем на каждый тик, и их теперь в обычных случаях ~2, в исключительных — до 5. Но это не давало гарантии, что React обработает близкие во времени изменения за один шаг свёртки, т.е. выполнит согласование и отобразит изменения виртуального DOM в реальный.

Однако этот процесс можно взять под контроль при помощи функции batch из пакета React + Redux. Собственно, суть этой функции — гарантировать обработку ряда синхронных изменений стейта за одну фазу согласования. Круто же, разве нет?

Но этого мало, у нас все ещё остаётся ряд компонентов, подписанных через connect на обновление данных из стейта. И они могут меняться очень часто, хотя делать этого не надо.

Тут нужен пример. Например, есть компонент , который

  1. показывает оставшееся время;
  2. показывает очки, набранные игроком.

Это был классический React.PureComponent, который обёрнут в connect и в mapStateToProps. Он забирает из стейта поля elapsedTime и score . Score меняется нечасто, а elapsedTime — после каждого тика. Преобразование elapsedTime в минуты-секунды происходит в методе render. Это значит, что сам компонент ререндерится по частоте FPS, то есть в каждом кадре у этого компонента выполняется shouldComponentUpdate. У HOC’a connect тоже выполняется — shouldComponentUpdate в каждом кадре.

Вот варианты, как можно «оптимизировать» этот компонент и добиться наибольшей эффективности, как в этом приложении:

  1. Написать свою функцию shouldComponentUpdate, в которой elapsedTime будет сравниваться как секунды (с последующим приведением к привычному формату времени). Это вариант, но он не избавит от жизненного цикла HOC’a connect.
  2. В mapStateToProps сразу вернуть секунды. За счёт того, что у нас чистый компонент, фактический ререндер будет происходить один раз в секунду. Но это всё ещё не избавляет нас от ЖЦ connect’a.
  3. Перейти на хуки и использовать useSelector. Вариант тоже хорош, т.к. селектора будет всего два. Это, вероятно, будет быстрее, но не факт.
  4. Посмотреть на родительский компонент — он тоже обёрнут в connect, и он — самый верхнеуровневый компонент приложения. То есть наверняка он и останется таким, его не оптимизируешь. А значит он может передать нашему ScoreBoard готовое значение в секундах.

Сказано — сделано! У ScoreBoard’a больше нет connect, зато есть две пропсы, прилетающие сверху от родительского компонента. Родительскому компоненту нужно не забыть возвращать из mapStateToProps сразу секунды, чтобы он сам по себе не стал слишком часто обновляться.

Ну и так по аналогии со многими компонентами, использующими connect. После этих манипуляций осталось всего два компонента, которым действительно нужно получать актуальное состояние как можно чаще — компонент-обёртка над нашей картой и компонент-обертка над canvas-элементом, в который three.js рендерит все игровые объекты (бомбы, самолёт, и т.д). Если посмотреть на логику методов render у обоих компонентов, то там будет:

return ref= />;
return ref= />;

Что бы ни происходило со стейтом приложения, на 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 у этих компонентов более никогда не вызывался. Шаги для этого такие:

  1. избавляемся от connect. Выпиливаем с корнями, вместе с mapStateToProps;
  2. пишем у компонента public shouldComponentUpdate() < return false; >— компонент из «чистого» превращается в «обычный»;
  3. достаём стор Redux в компоненте (вот как это можносделать) или просто useStore в случае хуков;
  4. подписываемся на изменений состояния приложения ( store.subscribe(() =>< /* … */>) );
  5. делаем требуемые манипуляции в колбэке на изменение состояния приложения;
  6. готово!

Получается примерно так:

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 не вызывают у вас необходимости срочно читать, что это такое;
  • имеете маломальский опыт в оптимизации приложений на этом стеке;
  • готовы не просто отойти от «лучших практик», но и внедрять откровенные антипаттерны с пониманием, к чему это приведет;
  • имеете опыт в мобильной разработке, если игра адаптирована для маленьких экранов.

Подумайте ещё раз, вдруг в вашей ситуации есть варианты лучше. Если нет, берите именно этот стек. Если хотя бы один пункт не выполняется, то я бы не стал брать эти технологии. Что брать на замену? Предлагайте варианты в комментариях.

Настало время полезных советов:

  1. На мой взгляд, разработка игры является тем случаем, когда архитектуру нужно развивать не планомерно, но на старте работ надо прикинуть, что и как будет. В этот момент сразу стоит выделить одну или несколько веток в стейте, которые будут часто меняться.
  2. Стремитесь, чтобы React’у не приходилось по 30 раз в секунду выполнять согласование для множества компонентов. В этом вам поможет первый пункт: не стоит завязывать компоненты на частоизменяемые значения стейта.
  3. Явно выделите стадии вашего приложения, потом это поможет отсутствием костылей.
  4. Изолируйте игровое время от физического. Дайте возможность подписываться кому угодно на изменение этого времени. В игре банально могут быть паузы и игровое время в этот момент останавливается, а физическое продолжает идти.
  5. Вся логика в игре должна основываться на игровом времени.
  6. Чаще запускайте вкладку Performance в вашем Хроме — так вы обнаружите проблемы раньше. Не забывайте устанавливать тротлинг CPU — так вы будете ближе к пользователям, далеко не у всех Intel i9.
  7. Найдите среди ваших тестовых девайсов какой-нибудь среднестатистический Андроид: в диапазоне цен 12–20К и с возрастом два–три года. Скорее всего, это ваш пользователь.
  8. Если найдете ПК со слабой видеокартой, будет очень хорошо. Если бы у нас у всех были маки, подозреваю, что мы бы сильно позже увидели проблем с производительностью. На таких устройствах очень удобно профилировать, и проблемы производительности на них заметнее.
  9. Вам точно будет легче, если вы на самом старте договоритесь с заказчиком о том, что не поддерживаете старые браузеры. Люди с IE11 вряд ли ваш пользователь, а проблем это доставит. Мы вообще отказались работать с Хромом меньше 70-го и Edge меньше 18-го (по мажорным версиям).
  10. Технология WebGL нова и далеко не всеми браузерами поддерживается на одном уровне качества. Где-то работает быстро, как в Хроме, а где-то, например в Firefox на linux, есть очевидные проблемы производительности. Будьте к этому готовы. Какую политику выбрать — решать вам. Можете сразу отправлять в бан-лист, например. Мы сделали специальную плашку, которая предупреждала игроков о том, что «могут быть проблемы с производительностью на вашем устройстве», и просьбой попробовать другую конфигурацию.

Проблемы, которые вас точно ждут:

  1. Firefox. Он просто медленнее Хрома. В частности, в моментах работы с WebGL, но не только — посмотрите пример с оператором spread. FPS в Firefox стабильно раза в полтора ниже, чем у Chrome. Благо, это не самый популярный браузер, тем более на мобилках.
  2. IPhone. Разработчики Safari ведут себя на уровне IE6 в 2К20 и наглейшим образом отказываются чинить доисторические баги своей платформы. В айфонах банально не может нормально работать событие ресайза, что очень сильно стреляет, когда пользователь переворачивает экран. Про выезжающую снизу плашку, которую нужно отдельно обрабатывать, я вообще молчу. Ну и их политики безопасности. Нам так и не хватило времени победить звук в айфонах — нельзя взять и просто так проиграть какой-либо звук.
  3. Читеры. Они точно будут. Причём некоторые из них могут быть очень наглыми. У нас был случай, когда забаненный игрок писал в техподдержку о том, что все призы достанутся сотрудникам компании (хотя, конечно, правилами это явно запрещено). Предусмотрите античит.
  4. Недовольные результатами. Некоторые могут видеть читеров вообще в любом, кто набрал больше, и могут завалить жалобами и упрёками. Хотя нередко результат, который они посчитали читерским, и близко не был к тому, который мы сами «набивали» без всяких читов ещё во время тестов.
  5. Если аудитория сильно отличается по возрасту и игровым навыкам (а это наш случай), вам придётся уместить в трёх–пяти картинках всё знание о том, что и и как надо делать в игре. Самостоятельно эта часть аудитории разбираться не будут.

Проблемы и трудности были, но в итоге получилось одно приложение, которое работает на всех устройствах. Не нужны отдельные приложения под iOS, Android и Web и три команды разработки под каждую платформу.

  • Блог компании 2ГИС
  • JavaScript
  • Разработка игр
  • ReactJS

Metro: Redux скачать торрент

Удивительная и качественная подборка сразу из двух частей серии Metro, созданная в оригинальном жанре survival – экшен с элементами шутера, зрелищными спецэффектами, и качественным сюжетом, по мотивам одноименного произведения Дмитрия Глуховского. Стоит заметить, что над воплощением всех особенностей продукта трудились, не жалея собственных сил и времени, девелоперы из украинской студии 4A Games. Поэтому, если вы хотите опробовать измененную версию «Метро», причем сразу обновления для двух частей, тогда рекомендуем Metro: Redux, скачать торрент, воспользовавшись услугами нашего портала, что крайне удобно и просто. Итак, давайте поближе рассмотрим особенности этих игр, и ознакомимся с отличиями от оригинала.

Графика

Во-первых, визуализация. Картинка в обеих играх существенно изменяется благодаря внедрению нового, авторского движка студии – 4A Engine. Стоит подчеркнуть, что движок привносит в обе игры новую систему освещения, благодаря которой окружение смотрится ярче, живее, и глубже прорисовано. Но при этом никуда не делась та самая атмосфера «уныния» и «безнадежности», которую можно почувствовать в каждом фрагменте этого пост-апокалипсического мира, реализованного в московском метро. Правда, под новым освещением «убогие» модели NPC, стали смотреться еще хуже. Отсутствие эмоций, угловатая анимация, квадратные конечности и лица – так второстепенных героев не делают уже с начала 3 тысячелетия! Поэтому, если вы хотите опробовать улучшенную графику в обеих частях, и кроме того, появились новые фрагменты уровней, коих не было раньше, тогда рекомендуем скачать Metro: Redux, через торрент, что можно сделать запросто с этой страницы.

Игровая механика

Во-вторых, особенности игровой механики. Кардинальных перемен в игровом процессе так и не оказалось. Несмотря на то, что разработчики обещали перемены в геймплее, исправить низкий уровень искусственного интеллекта противника, сил им, как видим, не хватило. Соперники все также выбегают прямо навстречу пулям, выпущенным из автомата игрового персонажа. Но, с другой стороны – теперь они не увидят Артема в кромешной тьме, или с дальнего края локации, что добавляет очков в пользу стелс-прохождения игры. Еще одно существенное изменение – в первой части Metro 2033 теперь есть то же оружие, что и в сиквеле. Поэтому, если вы уже прошли каждую из игр, то вам вряд ли захочется вновь отправиться в мир «Metro», но с другой стороны – для игроков, которые играли только в первую часть, Metro: Redux, скачать через торрент станет невероятно выгодным предложением!

Особенности Metro: Redux

  • Улучшенная визуализация. Графика в игре стала лучше проработанной и зрелищнее, благодаря внедрению нового движка от студии. Стоит заметить, что текстуры стали более насыщенными. И вдобавок к этому, появилась новая система освещения, которая делает мрачные коридоры немного ярче, отчего отчетливо бросаются в глаза изменения.
  • Та самая атмосфера. Но, несмотря на все улучшения, игродели сохранили традиционную атмосферу уныния, тоски и безнадеги, которая царит на протяжении всего прохождения. Среди еще некоторых изменений – это появление новых локаций, коридоров в некоторых местах, но они особо не влияют на развитие сценария.
  • Геймплей. В плане игрового процесса изменений мало. Искусственный интеллект не стал умнее, и все также игра будет представлять собой динамичный «тир». Но, теперь противники не будут находить Артема в абсолютно мрачных подземельях, и не смогут увидеть его сквозь препятствия.
  • Оружие из сиквела появилось в первой части. Еще одно небольшое изменение, которое внедряет все оружие из сиквела в первую часть серии Metro 2033. Кроме того, и в Last Light появились новые пушки, что не может не радовать фанатов серии.

На этой странице по кнопке ниже вы можете скачать Metro: Redux через торрент бесплатно.

Скриншоты Metro: Redux

Metro: Redux Metro: Redux Metro: Redux Metro: Redux Metro: Redux Metro: Redux

Видео к игре Metro: Redux

Системные требования Metro: Redux

  • ОС: 64-бит Windows Vista/7/8/10
  • Процессор: Двухъядерный с частотой 2.2 ГГц
  • Видеокарта: 512 Мб, DirectX 10
  • Оперативная память: 2 Гб
  • Свободное место на жестком диске: 8.97 Гб

Информация о торренте

Тип издания: RePack.
Версия игры: 1.0.0.3 Update 7.

В состав репака входят игры: Metro 2033 Redux, Metro Last Light Redux.

Alan Wake 2

Alan Wake 2 68.00 ГБ

ARK Survival Ascended

ARK Survival Ascended 79.93 ГБ

Call of Duty Black Ops Cold War

Call of Duty Black Ops Cold War 79.43 ГБ

Stray Souls

Stray Souls 15.69 ГБ

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *