Как перевести работающую игру с Flash на HTML5, не переписывая клиент с нуля и не нарушая привычный опыт игроков? В колонке для App2Top руководитель разработки SuperCity Кирилл Иванов рассказал о постепенной модернизации проекта, причинах сохранения старых инструментов и автоматизации процессов, которая позволила сократить отдельные задачи с нескольких дней до нескольких часов.
В теории модернизация приложения с устаревшим кодом выглядит просто: определить проблемную технологию, заменить ее современным стеком, убрать старые зависимости и продолжить разработку. На практике все сложнее. Мы столкнулись с этим при модернизации SuperCity — игры, которая работает уже 15 лет.
SuperCity была запущена в 2011 году. Сегодня ее клиент построен на TypeScript и PixiJS, а на бэкенде по-прежнему используется PHP. При этом отдельные части системы сохраняют решения эпохи Flash. Художники продолжают работать в Adobe Animate, контент должен оставаться совместимым с существующими производственными процессами, а часть браузерной инфраструктуры — поддерживать интерфейсы взаимодействия, изначально спроектированные под Flash Player.
Поэтому для нас модернизация никогда не означала замену каждого старого компонента. Наша задача состояла в другом: постепенно отказаться от технологии, которую перестала поддерживать индустрия, сохранив игру, знакомую аудитории.
Первая миграция решила проблему игроков, но не разработки
Первый серьезный шаг по отказу от Flash мы сделали, когда браузеры начали прекращать его поддержку. SuperCity должна была продолжать работать без Flash Player, однако немедленно переписывать весь клиент мы не стали.
Вместо этого мы использовали слой конвертации, который преобразовывал существующий код на ActionScript в JavaScript для рабочей версии игры. Одновременно мы адаптировали PixiJS так, чтобы он воспроизводил поведение, которого игра ожидала от Flash Player. Для пользователей проблема была решена: SuperCity продолжила работать в браузере без старого плагина.
Но из процесса разработки Flash не исчез. Мы по-прежнему писали на ActionScript и конвертировали код при сборке. При внесении изменений приходилось учитывать дополнительный слой, усложнявший отладку и поддержку.
Со временем все заметнее становилась и другая проблема: Flash превращался в изолированную технологию. Все меньше инженеров хотели с ним работать, новые инструменты почти не появлялись, экосистема перестала развиваться, а доступная нам внешняя экспертиза сокращалась.
В какой-то момент мы поняли, что реалистичной альтернативы миграции не осталось. Без развития технологий вокруг SuperCity поддерживать саму игру становилось бы все сложнее. Однако это еще не делало полное переписывание правильным решением.
Успешная live-игра — больше, чем код
Для зрелой игры переписывание клиента создает риск, которого нет у многих обычных программных продуктов. Игроки взаимодействуют с интерфейсом не несколько минут, чтобы выполнить какую-то задачу. Они могут возвращаться в один и тот же продукт годами. Они знают, где что находится. Понимают, как работают системы. Они практически подсознательно выучили визуальные паттерны и правила взаимодействия. Эти накопленные знания становятся частью самого продукта. Совершенно новый клиент может воспроизводить те же механики и данные, но при этом ощущаться как другая игра.
Я считаю это различие особенно важным для игр.
В утилитарном приложении изменение интерфейса может доставлять неудобства, но пользователь обычно способен освоить новый путь к тому же результату. В игре интерфейс, обратная связь, ритм и накопившееся чувство знакомого продукта сами являются частью опыта. Заменив все это одновременно, вы рискуете заставить давних игроков заново изучать то, что они никогда не просили менять. Существовала и более традиционная инженерная проблема. За годы работы SuperCity накопила большое количество интеграций и платформенных зависимостей. Пересоздание их всех с нуля, повторная валидация и полный регрессионный прогон всего продукта потребовали бы значительных инвестиций. Фактически команда взяла бы работающую игру, заново построила значительную ее часть, а затем еще и заплатила бы за то, чтобы доказать, что новая версия работает так же, как старая. При этом не было никаких гарантий, что результат создаст сопоставимую бизнес-ценность.
Поэтому мы выбрали постепенные изменения: измерять эффект каждого шага и не трогать работающие части системы без четкой причины.
Сохраняйте контракт, меняйте то, что находится за ним
Одним из наших ключевых архитектурных решений стало сохранение интерфейса взаимодействия, на который опиралась игра. Это позволило не переписывать сразу все зависимые системы.
Flash Player фактически выполнял роль контракта: через известные вызовы игра могла попросить его отрисовать объект, воспроизвести или изменить звук, выполнить другую операцию. После отказа от Flash мы воссоздали этот контракт. Реализация под ним изменилась, но вызывающему коду не требовалось знать детали нового окружения.
Если игра просит показать анимацию, этой части кода не должно быть важно, какая технология в итоге ее отрисовывает — Flash Player или Pixi.
Новый слой получает знакомую команду и обеспечивает ожидаемое поведение. Так мы заменили критически важную часть стека, не перестраивая одновременно все связанные системы.
У подхода есть цена: слой совместимости сохраняет технический долг и со временем требует дополнительной адаптации. Но переписывание всех зависимых систем обошлось бы значительно дороже и создало бы больше рисков.
Слой совместимости может отличаться от архитектуры, которую мы выбрали бы для новой игры. Однако при модернизации действующего продукта приходится учитывать все, что уже работает.
Переход на TypeScript потребовал миграции целой экосистемы
Следующим нашим крупным шагом стал отказ от ActionScript непосредственно в разработке и переход на TypeScript. Он завершился спустя годы после первой браузерной миграции.
Одна из причин — приоритеты. Пока инженеры обновляют технологическую основу, live-игра продолжает выпускать контент. События должны запускаться, серверы — справляться с изменениями нагрузки. Внешние платформы вводят обязательные требования, а продуктовые возможности появляются и исчезают. В разные моменты эти задачи оказывались срочнее внутренней миграции.
Другая причина — масштаб зависимостей. За годы работы мы создали вокруг SuperCity утилиты для конвертации ассетов, процессы сборки, внутренние приложения и инструменты для разных специалистов. Зависимость от Flash не ограничивалась клиентом.
Если бы мы перевели на TypeScript только клиент, оставив остальное без изменений, узкое место просто переместилось бы в другую часть производственного процесса.
Миграция касалась не только того, что игроки запускают в браузере. Нам также пришлось перестроить множество внутренних процессов вокруг игры.
Эта менее заметная часть перехода сама по себе стала крупной инженерной задачей.
Старое не означает неправильное
Арт-пайплайн показывает, почему мы не считаем модернизацию поводом удалить все, что связано с Flash. За годы существования SuperCity накопилось около 80 ГБ графических ассетов: зданий, декораций, персонажей и другого контента. Художники по-прежнему используют Adobe Animate.
С технологической точки зрения инструмент может выглядеть очевидным кандидатом на замену. Но с точки зрения производства расчет другой: новый инструмент должен обеспечивать как минимум прежнее качество и скорость работы.
Если качество ассетов снижается, страдает продукт. Если оно сохраняется, но каждый релиз требует больше времени, страдает производство. Мы изучали альтернативы, однако пока не нашли замену, преимущества которой оправдали бы перестройку всего процесса.
Для нас возраст технологии сам по себе не является достаточной причиной для ее замены. Компонент становится приоритетом для модернизации, когда начинает создавать существенные ограничения.
Иногда лучше модернизировать не сам инструмент, а процессы вокруг него
Сохранение Adobe Animate не означает, что работа с графикой осталась прежней. Раньше художник зачастую не мог точно увидеть, как ассет будет вести себя в игре, пока разработчики не подготовят рабочую сборку. Это удлиняло цикл обратной связи.
Арт нередко создается задолго до выхода новой функции. Если проблема конвертации, артефакт рендеринга или другое визуальное отличие обнаруживаются только при подготовке тестовой сборки, исправлять их приходится слишком поздно.
Мы создали браузерный инструмент предпросмотра — упрощенную версию игры. Художник может загрузить ассет и сразу увидеть, как он выглядит в игровом окружении. Изменение цветов, искажение пикселей и другие проблемы конвертации становятся заметны сразу.
Это изменило и распределение ответственности. Раньше разработчики собирали ассеты, готовили сборку и помогали разбираться с обнаруженными проблемами. Теперь автор ассета может самостоятельно проверить результат и подготовить его к следующему этапу.
Контроль качества сохраняется, но инженерам больше не нужно вручную связывать каждый этап производства. Легаси-инструмент остался, а процессы вокруг него изменились.
Более масштабная цель — убрать разработчиков из работы, которая не требует разработчиков
Со временем этот принцип вышел за пределы работы с графикой. За последние несколько лет мы перестроили значительную часть внутренних инструментов в систему, которую я бы назвал внутренней ERP для игры.
Исторически инженеры участвовали почти в каждом этапе подготовки релиза. Переводы, арт, игровые и промоконфигурации, другие материалы в итоге сходились на разработчиках, прежде чем можно было собрать рабочую версию. Инженерная команда становилась узким местом.
Новые инструменты разделили зоны ответственности. Специалист, отвечающий за игровую конфигурацию, может самостоятельно ее опубликовать, а система знает, как собрать итоговый результат. Гейм-дизайнер может изменить баланс или подготовить прототип новой функции, подготовить изменение и протестировать его, не прося разработчика вручную проводить каждый артефакт через пайплайн.
Процессы, которые раньше требовали у нас нескольких дней, координационных встреч и участия инженеров, теперь могут занимать несколько часов. В некоторых случаях само взаимодействие стало сводиться всего к нескольким действиям во внутреннем инструменте.
Главный результат заключается не в том, что все стали техническими специалистами. Скорее наоборот. Гейм-дизайнер больше не должен разбираться в бранчах Git-а, чтобы протестировать изменение баланса. Нарративный специалист больше не должен понимать внутреннее устройство пайплайна, чтобы обновить контент. Художнику больше не нужен разработчик только для того, чтобы увидеть, как ассет будет выглядеть в игре.
Canvas требует отдельного подхода к автоматизации тестирования
Переход на HTML5 не создал проблему автоматизированного браузерного тестирования с нуля. Flash и раньше был плохо доступен стандартным инструментам. Но после миграции мы лишились привычных возможностей отладки Flash, а HTML5 canvas принес свои ограничения.
Для браузерной автоматизации canvas может выглядеть как черный прямоугольник. В нем нет удобных DOM-элементов, соответствующих каждому зданию или компоненту интерфейса.
Поэтому визуальные проверки требуют других подходов. У нас есть внутренние инструменты отладки для изучения слоев рендеринга. Часть проверок можно выполнять с помощью изображений и сравнения скриншотов. Однако многие сценарии все равно сложнее автоматизировать, чем в обычном веб-интерфейсе.
Базовые сквозные сценарии мы уже автоматизировали: можно развернуть сборку, запустить игру, привести ее в нужное состояние и проверить, например, размещение здания или сбор ресурса.
Более сложная проблема связана с состоянием live-игры. Два пользователя могут видеть разные окна, события, предложения и интерфейсы в зависимости от платформы, прогресса, когорты и времени. Тест, работавший вчера, завтра может столкнуться с другим набором событий или предложений LiveOps.
Автоматизация должна учитывать не только место нажатия, но и причину, по которой состояние игрока отличается от ожидаемого. Для некоторых сценариев полное решение этой задачи сегодня обошлось бы дороже ручного тестирования.
Мы оцениваем автоматизацию по тому, устраняет ли она реальное ограничение. Сам по себе рост доли автоматизированных процессов для нас не является целью.
Иногда тестировать приходится в рабочей среде
В долгоживущих играх возникают ситуации, когда ограничения внешней платформы не позволяют полноценно воспроизвести нужные условия до релиза. Во время недавней обязательной миграции одной из платформ мы столкнулись именно с этим: определенное поведение можно было корректно проверить только в рабочей среде.
Такой подход был продиктован условиями платформы. Мы постепенно включали изменение для небольшой доли пользователей, наблюдали за системой и расширяли охват по мере роста уверенности в результате.
Этот пример показывает, что постепенная модернизация помогает управлять рисками. В крупной миграции неизбежны неизвестные. Возможность поэтапно внедрять изменение, измерять его эффект, корректировать или откатывать позволяет не подвергать риску всю аудиторию сразу. Для live-игры устройство развертывания обновлений тоже становится частью модернизации.
Главное преимущество — не сам TypeScript
Отказ от Flash изменил язык разработки, но одно из главных улучшений я вижу в расширении круга специалистов, способных работать над SuperCity.
Найти инженера, который знает Flash, хочет продолжать на нем писать, интересуется игровой индустрией и готов работать над зрелым продуктом, становилось все сложнее. TypeScript в значительной степени снял это ограничение.
Не менее важный результат — сокращение инженерного участия в повседневном производстве. Разработчикам больше не нужно вручную сопровождать каждый этап подготовки контента. Художники могут самостоятельно проверять больше ассетов, а гейм-дизайнеры — создавать прототипы и настраивать игровые системы.
Внутренние инструменты собирают материалы, которые раньше требовали целой цепочки людей и технических операций. Некоторые процессы сократились с нескольких дней до нескольких часов. Для нас это более содержательная метрика модернизации, чем полное отсутствие устаревших компонентов в кодовой базе.
Наша цель состояла в том, чтобы игру было проще продолжать развивать.
Модернизация легаси никогда не заканчивается
В SuperCity по-прежнему есть старый код, системы, которые мы хотели бы улучшить, и технологии, которые со временем могут быть заменены. При этом мы пересматриваем даже относительно недавно созданные части игры.
В своем подходе мы ориентируемся на метрики, а не на возраст технологии. Если что-то загружается медленно, мы изучаем проблему. После устранения самого существенного узкого места становится заметно следующее — и работа продолжается.
Результаты влияют на обе стороны продукта. Игроки получают более быструю загрузку, меньше сбоев и более быстрый отклик. Инфраструктуре при этом может требоваться меньше ресурсов для обеспечения того же качества работы.
Мы не можем однажды объявить архитектуру современной и перестать о ней думать. Для долгоживущего продукта модернизация — постоянная работа по сохранению возможности развиваться.
Начните с границ, с понимания того, что ни в коем случае нельзя ломать
Если бы я консультировал другую команду успешного продукта возрастом 10–15 лет, я начал бы с определения границ, а не с выбора нового движка. Чего команда хочет добиться? Что она способна изменить с учетом людей, технологий и ресурсов? Что нельзя сломать в процессе?
Для зрелой live-игры последний вопрос касается и инфраструктуры, и аудитории. Технически элегантная миграция может оказаться провальной, если разрушит привычный игрокам опыт.
Я также скептически отношусь к смене технологий ради подражания. Переход другой студии на Unity, Cocos или иной популярный стек сам по себе ничего не говорит о потребностях SuperCity. У каждого зрелого продукта свои ограничения.
Мой совет: сначала поймите, чего вы хотите, что вы можете сделать и что вы не можете позволить себе сломать. Все остальное нужно пропускать через здравый смысл.
Мы постепенно устраняли ограничения вокруг существующей игры. Flash исчез из повседневной разработки клиента. Слои совместимости защищали работающие системы, пока менялась их реализация. Внутренние инструменты позволили профильным специалистам самостоятельно выполнять задачи, ранее зависевшие от инженеров.
Мы внедряли автоматизацию там, где она давала ощутимый эффект, и сохраняли ручное тестирование там, где оно оставалось экономически оправданным. Такой подход позволяет менять технологии под работающей игрой, не заставляя ни аудиторию, ни команду начинать все заново.





