Представьте: вы пишете 2D-игру на Flame, но хотите добавить в неё полноценный 3D-мир. Звучит как боль? Разработчики из pleiondev решили эту задачу, создав мост между 2D-логикой и 3D-рендерингом. Результат — браузерный шутер River Sortie в стиле классического River Raid, где самолёт летит над бесконечной рекой, уничтожая танкеры и мосты.
🚀 Ключевая фишка — пакет flame_flutter3d. Он позволяет встраивать 3D-модели прямо в 2D-сцену Flame. Есть два режима: простой (одна модель через
Model3dComponent) и полный (отдельный 3D-мир с камерой и физикой). Во второй вариант и упирается River Sortie.💡 Архитектурно это выглядит как
Stack: снизу 3D-сцена, сверху 2D-логика Flame. Так сделано не случайно: в браузере 3D-поверхность — это platform view, и именно она ловит события мыши. Поэтому интерактивные элементы игры должны быть «выше» в дереве виджетов.⚡️ Главная проблема интеграции — синхронизация времени. Два независимых таймера (для 2D и 3D) неизбежно рассинхронизируются. Решение — единый тикер. Компонент
BridgeClock с приоритетом 1 << 20 запускается последним: сначала Flame обновляет логику, затем позиции переносятся в 3D, и только потом рендерится кадр.🔧 Координатные системы тоже разные:
Vector2 в Flame и Vector3 в 3D. Чтобы не путаться, введён класс BridgePlane. Он централизует преобразование осей. Например, в режиме ground (вид сверху) ось Y из Flame становится осью Z в 3D-сцене. Это предотвращает скрытые баги с зеркальным отражением объектов.⚠️ Есть и ограничения. В браузерах рендеринг 3D-контента через простой способ медленный: Flutter не композитит canvas напрямую, поэтому пиксели приходится считывать обратно. Это добавляет задержку в один кадр. Поэтому для полноэкранного 3D нужен именно полный режим интеграции.
📊 Производительность оптимизирована через инстансинг. Выстрелы — это отдельные компоненты Flame с хитбоксами, но отрисовываются они одним вызовом через
InstancedObject3dComponent. Это критично при частоте стрельбы до 5 выстрелов в секунду.🎮 Игра использует детерминизм через
HasFixedStep. Логика работает фиксированными шагами, поэтому трасса реки (генерируемая по seed) будет идентична на устройствах с экранами 60 Гц и 120 Гц. Столкновения обрабатываются стандартными хитбоксами Flame, а визуальные эффекты (крен самолёта, взрывы) отделены от игровой логики.🔗 Полезные ссылки
flame_flutter3d на pub.dev
Исходный код на GitHub
🔗 Полезные ссылки
📦 flame_flutter3d
💻 flutter3d
📰 Читать оригинал на Habr
FlutterPulse — канал о мире Flutter!
#flutter #dart #flutterpulse #flutterpulsehabr