Как стать автором
Обновить

Ускорение игрового 2D движка Flame до стабильных максимальных FPS на телефонах и ПК

Уровень сложностиСредний
Время на прочтение28 мин
Количество просмотров3.5K
Всего голосов 12: ↑12 и ↓0+12
Комментарии36

Комментарии 36

Очень познавательно!

Всё круто. Только у меня вопрос. Как тогда работали игры типа baldur gate, Arcanum, fallout, на железе на порядок слабее? Оверхед на старте от используемых фреймворков и инструментов? Я замечу, что многие старые игры не использовали ускорение 3d. К примеру fallout tactics идёт комфортно на pentium 233 mhz, Arcanum 400 mhz, disciples 2 300 mhz. Это всё при рисовании картинки на ЦПУ.

Я понимаю, что увеличилась цветность, разрешение экрана. Но все остальное осталось прежним, вывод спрайтов, анимации. На железе котрое просто не сравнимо с аналогичным 2000-ых годов.

ну как минимум никакого PNG

Неужто в движке Flame используется настолько неэффективно gpu, для простой 2D графики?

GPU пофигу, он на расслабоне большую часть времени, даже если у вас FPS низкий.

Тут надо вообще начинать с того, что Flutter считает за FPS. Если у вас процессор не успевает обсчитать всю логику за 16 милисекунд, то команды на графический процессор будут формироваться дольше и позже, и GPU очень-очень быстро отрисует вам кадр, но команду на отрисовку он получит позже, чем должен.

Конкретно у Flame, по моим ощущениям, проблемы в том, что:

  1. Разработчики движка и игр на движке как-то в основном мыслят играми уровня "три в ряд", по моим ощущениям. Мы сделали игру, где скачет пять шариков и один квадратик - ура, мы счастливы, это успех, наш движок супер! Это не даёт команде смотреть на некоторые проблемы под другим углом

  2. Как следствие, некоторые архитектурные решения не оптимальны, и в "нагруженных" сценариях приводят к драматическому уменьшению FPS. Но об этом мало кто знает, потому что "мы делаем три в ряд, у нас всё хорошо, Flame - зрелый движок для разработки игр"

  3. На текущий момент цель команды - это стабилизировать имеющуюся ветку разработки, так что на какие-то радикальные архитектурные изменения они не готовы, максимум - вставлять костыли, чтобы предоставить workaround для самостоятельного фикса проблемы. Поэтому ожидать каких-то радикальных улучшений в плане скорости сейчас не стоит.

  4. При этом ребята жестко озабочены следованием какого-то архитектурного плана, которого надо придерживаться, так что даже предложив рабочее решение, которое решает проблему и даёт новые фичи - есть риск получить отказ, потому что "эта архитектура недостаточно хорошо, это решение предлагает пользователю делать игры не так, как их дОлжно делать" и т.п. С этим приходится мириться.

  5. Часть модулей там просто никто не поддерживает, команда маленькая и рук не хватает. Тот же модуль для работы с Tiled ни то жив ни то мёртв, в чатиках порой возникает какое-то движение, какие-то фиксы мелкие, но это всё и близко не напоминает какой-то мощный прогресс.

  6. Flame в основном состоит из "максимально общих решений". Взять те же столкновения объектов. В множестве игр будет достаточно расчитывать столкновения между квадратами и прямоугольниками, а то и просто кругами, но даже такие фигуры Flame обратабывает как абстрактные многоугольники - более общий и более дорогой алгоритм, но зато точно везде будет работать. Аналогично с общим игровым циклом - в процессе там происходит много всякого, что можно бы вообще отключить до возникновения какой-то особой ситуации (например, ресайз окна), но по-умолчанию Flame выполняет этот код на каждом тике - "ну а мало ли чего?" - вот возможности процессора и улетают в трубу...

Вот... и если бы перед разработчиками стояла задача написать конкретную игру с конкретной мезханикой - всё было бы гораздо проще и оптимизированнее, чем при подходе "мы пишем архитектурно и идеологически правильный движок, обязательно делаем ревью каждого мерджреквеста, обязательно пишем документацию и автотесты... и да. нас всего 5 человек, из них трое большую часть времени заняты на основной работе" =)

Спасибо за ответы. Стало более понятно, почему так происходит. Даже современное железо, не сможет вытянуть не оптимизированный код. Оптимизация forever!

Угу... Я тут недавно писал о том, что даже forEach можно заставить в определённых условиях работать в 15 раз быстрее... Если найти в системе штук 10 таких мест и все затюнить - тоже получится прирост. В общем, каждая кроха может внести свой вклад.

Но языки высокого уровня как-то приучают людей решать проблемы "грубыми мазками", часто отдавая приоритет красивым интерфейсам и синтаксическому сахару, когда во главе угла стоять должно совсем другое. Но более быстрый код порою хрен прочтёшь, даже если это ты сам писал всего лишь вчера :-)

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

Это не сверх технологии.

Ну я ж не говорю, что он специально получается запутанный, просто появляется куча дополнительных каких-то телодвижений, нужность которых с первого взгляда не очевидна, особенно для нового человека, который впервые зашел на проект и не вполне понимает, какая проблема этим куском решается, и что вообще такая проблема есть. Вот и кажется при первом взгляде "о боже, что за макаронный монстр, я бы проще сделал!"...

НЛО прилетело и опубликовало эту надпись здесь

а минус за что? вы попробуйте в любой из указанных игр спрайты сделать в PNG и посмотрите как у вас всё встанет колом.

Какие ещё варианты с поддержкой прозрачности? Я знаю только gif, но не смотрел различия в весе файлов

Вообще юзать пнг по крайней мере в релизной версии это зашквар. В мобилках так и подавно. Если у вас 20мбат пнгешек то это несколько сотен метров в raw формате которые очень больно обрабатываются мобильными ГПУ. Вам нужно смотреть в сторону сжатых форматов типа astc. Так же могу порекомендовать почитать про ktx.

Правда я уверен что этот движок ничего не знает ни про какие сжатые форматы и это так и будет без толку занимать сотни метров памяти и насиловать не топовые ГПУ.

P. S. Ktx vulkan нужен конечно же.

Благодарю, очень интересно будет посмотреть. В первый раз слышу про такие форматы

Мобильные gpu, умеют конвертировать на лету в сжатый формат при загрузке?

Понял. Но это вес всех пнг, а так на экране только девять маленьких картинок суммарным разрешением 1024 на 760. Так что я думаю можно пренебречь здесь уже оптимизацией. Да и у Flame нет никаких трудностей в отображении ПНГ на игровом поле от слова совсем.

Просто к сведенью. Видеокарта не работает с png от слова совсем. Браузер каждую png распаковывает в битмап. 1024x760 RGBA8 UNorm это 3.0 MB. На некоторых мобильных устройствах размер текстуры будет изменён до квадрата двойки по большей стороне. Т.е. станет 1024x1024 4.0 MB. А сжатая текстура будет весить 0.7 MB в ETC2 и отправляется в память видеокарты как есть. Но сжатые текстуры придётся делать в разных форматах под разные платформы. В идеале этим должен заниматься движок на котором делается игра.

Ну тут нет каких-то особых способов повлиять.

Можно либо полезть в исходники Skia и посмотреть, что же она делает с картинками под капотом, получить некое знание, и жить с ним дальше, т.к. повлиять на этот процесс всё равно не получится на уровне Dart. Мы просто сможем сказать "да, всё плохо" или "да забейте, всё хорошо".

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

На уровне языка Dart есть только разделение на растризованную картинку и объект с записанными командами отрисовки. Всё. Не важно, грузим мы в Flutter jpg, png, bitmap или поток байтов со звуковой карты :-) В конечном итоге он пойдёт на видеокарту либо в одном либо в другом формате, и на то, что у этих форматов под капотом мы никак воздействовать не можем.

Ну тут нужно ресурсы Baldur's Gate изучать, я не в курсе какой формат они использовали, но точно не PNG. Вообще редко в играх был какой-то распространенный формат графики, все пытались оптимизировать данные как по весу, так и по скорости. Иногда мелькали PCX, TGA, а GIF слишком тяжёлый для использования в играх.

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

Вот эта статья, а вот демка, которая даже в мобильном браузере работает на приличных FPS, можно по-зумить, увидеть как динамически подгружаются рядомстоящие карты. а все пространство без карт заполняется динамически сгенерированным контентом.

Вот вам и ответ на вопрос, "как тогда работали игры типа baldur gate, Arcanum, fallout, на железе на порядок слабее" - алгоритмы!

Я пока стараюсь сильно об этой либе не кричать, потому что документацию ещё не описал нормально, хотя что-то уже есть + тестирую её в прикладных условиях и по ходу вношу некоторые изменения... некоторые. правда, приходится контрибьютить непосредственно в Flame, что несколько дольше.

В общем, если заморочиться оптимизацией и подобрать алгоритмы, то даже на одном потоке можно иметь в игре 500к объектов и более - и всё будет работать шустро даже в условиях браузера и JS.

Но я бы не сказал, что переписывать Broadphase было легко. Я полтора года назад начал этим развлекаться, и ещё , как видите, в процессе.... Так что со своей стороны все-таки не рекомендую начинать этот путь с нуля, если у вас есть лимиты во времени, сроках, ресурсах и т.п.

Да, но даже с тюнингом нет вообще понятия столкновение с землёй и какая-то возможность работать с этим. Нет сложения этих сил на тело, нельзя создать любое тело для столкновения и так далее. Всё это не позволяет сделать более менее приятно ощущаемую игру. Надеюсь, что допишите движок. В плане отображения на экране и классов, которые с этим связаны - использовать Flame ну очень приятно. Да и я считаю это основным в игровых движках - именно картинка. Логику ты можешь с нуля сделать под себя и пользоваться

Ну я про физику сейчас вообще не думаю: если система неудовлетворительно справляется с задачей сказать, перекрываются ли объекты А и Б, а также испытывает трудности с их отображением в достаточном количестве - то о какой тут физике вообще можно говорить)) Хотя у них же есть физический движок forge2D, но мне даже не интересно смотреть, честно, что там по производительности, после того что я увидел в базовом collision detection, обработке касаний с жестами и в рейтрейсинге...

Ваша демка, что на i7-7700, что на Snapdragon 835 при попытке зума уходит в загрузку на 30 секунд. Я, конечно, не эксперт, но с такими таймингами тут оптимизацией даже не пахнет. И там, и там Chrome последней версии.

2-3 фпс при таком масштабе и погрузка около минуты если сдвинуть карту хоть немного.
2-3 фпс при таком масштабе и погрузка около минуты если сдвинуть карту хоть немного.

Ну если резко отзумить на максималку - то это всё равно что попытаться в Morrowind открыть сразу всю карту и жаловаться, что она долго прогружается. А мне же надо продемонстрировать как-то чисто техническую возможность отзумить ооооочень далеко.

В рамках конкретной игровой механики должно стоять своё ограничение на максимальный зум, в зависимости от целесообразности, а при слишком больших "отзумах" вообще нужно показывать упрощённую карту с меньшей детализацией, но это отдельная и пока не реализованная история.

А, да, и в каждом квадратике с кирпичами - по 400 объектов, для которых теперь проигрывается анимация и считаются столкновения + потенциальная игровая логика. Итого, сейчас на экране чуть менее чем 30 * 15 * 400 = 18 0000 объектов, котрые все пришлось прогрузить и активировать, а за экраном ещё такая же куча объектов, которые предзагружены, но не рендерятся, а при сдвиге в сторону к ним докидывается ещё приличная пачка...

В общем да, без проработки механизма различных уровней детализации на больших отзумах ничего делать будет невозможно. Но без оптимизаций вообще вы и свои 3 FPS на таких зумах не получите. Тут же не просто тупо картинка, её зумить как раз нет никаких проблем.

Плюс к этому она содержит 14 слоёв тайлов и 4 слоя объектов. И вот тут начинаются проблемы с отображением этого всего.

Для чего такое количество слоёв. Какую задачу это решает?

Такой слоёный пирог нужен, чтобы сделать иерархию объектов по глубине, считайте это осью Z из 3D графики.

Во-первых - в ран тайме компилировать картинку я не вижу смысла - так как у меня карта не меняется. Во-вторых - если карта рандомная - можно заранее сделать различные подложки и прочее, а лабиринт загружать уже походу - это не затратно. Поэтому в итоге Вы всё равно будете рисовать карту, чтобы это было Вам удобно, потому что она никак не повлияет ФПС в игре, потому что превратится просто в картинку. А почему так много слоёв получается - на одном слое земля, на один слой выше - грязь, на один слой выше ведро, на один слой выше - ствол дерева, на один слой выше - гриб для красоты. Ещё слой выше - листья, которые анимированно падают с дерева. Уже 6 слоёв. Допустим - это всё на горе, т.е. все остальные слои должны быть ниже этих. Уже 12 слоёв. Добавляем ещё слои для функции автокарты и в итоге получаем примерно такое же количество) Иначе невозможно сделать интересную картинку

Сколько слоев в Arcanum, не знаете? Картинка довольно интересная. И автокарта имеется, деревья, камни.

В fallout tactics вообще 3 уровня тайлов, под землёй, на земле и на крыше. И так же есть и анимация и полно анимированных тайлов. И системные требования просто смешные.

Возможно сам подход к разработке и излишнее усложнение реализации, диктует повышение требований к железу?

Я просто не могу отделаться от впечатления прошлых подобных игр и их графики, в сравнении с графикой в данной статье.

Нет, понятное дело. Фаллаут тактикс не написан на flutter) Всё дело в этом. На компьютере даже когда просто заполняю всё неудаляемыми объектами для дебага у меня 80 фпс. На телефоне это будет уже около 15-ти. У меня сейчас тоже всё прекрасно работает с любым количеством слоёв. Просто в самом начале так проще рисовать. И вообще так рисовать именно проще. А что касается красоты - это купленные ассеты, поскольку я СОВСЕМ не художник, я сугубо программист. Поэтому я не могу нарисовать классный пейзаж морской и впихнуть его в игру. Приходится лепить просто из кубиков. А из кубиков такого вот механизма как в аркануме в пустыне ты не сделаешь)

Да и требования - я все тесты делаю помимо своего Самсунга А32 на Xiaomi A1 семилетней давности - и там тоже всё супер быстро работает. Так что требования у меня тоже сейчас смешные) Не говоря про любой ПК, даже супер старый.

Была бы игра для компьютера - я бы делал её на с++, естественно)

Тут уж надо проводить деконструкцию каждой конкретной игры... Я в своих поделках, в целом, тем же Арканумом и Фолычем вдохновляюсь, но хочется сделать при этом какую-то реюзабельную архитектуру, потому что сама игра, может ,и не будет иметь столько ценности, сколько возможность собрать на ее движке ещё что-нибудь.

Улучшение движка - это не писать на движках

Где нарушилась преемственность в программировании, когда то, что рисовалось быстро, теперь требует каких то серьёзных вычислений, причём с той же самой картинкой.

Блин, у нас тут Ворд и Ексель в гуглодоках на жабасурипте в браузере требуют 16 гигов оперухи и новый i7, когда всё то же самое работало у меня на пентиум 1 и win 95. Я с каждой новостью о выходе нового процессора всё больше содрагаюсь, что софт теперь станет ещё более херовым, и придется свой комп обновлять просто чтобы работало то, что работало и раньше.

«Нужно бежать со всех ног, чтобы только оставаться на месте, а чтобы куда-то попасть, надо бежать как минимум вдвое быстрее!»

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории