- Kotlin 100%
FPS усредняется по окну в 500 мс на кадрах withFrameNanos. Release подписывается debug-ключом — так же, как в Flutter-шаблоне, чтобы сборку можно было ставить на устройство. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| androidApp | ||
| gradle | ||
| shared | ||
| .gitignore | ||
| build.gradle.kts | ||
| gradle.properties | ||
| gradlew | ||
| gradlew.bat | ||
| README.md | ||
| settings.gradle.kts | ||
Life Particles (Kotlin / Compose Multiplatform)
Порт Flutter-приложения LifeParticles на Kotlin Multiplatform + Compose Multiplatform. Цели сборки: macOS (desktop) и Android.
Симуляция «particle life»: три типа частиц, матрица сил между типами, образование и разрыв связей, пространственная сетка для ускорения расчёта. Тап по холсту удаляет ближайшую частицу или добавляет новую выбранного типа.
Запуск
./gradlew :shared:run # macOS
./gradlew :androidApp:installDebug # Android (нужен подключённый девайс или эмулятор)
Сборка артефактов:
./gradlew :shared:packageDmg # .dmg для macOS
./gradlew :androidApp:assembleRelease # APK
Требуется JDK 17+ (JAVA_HOME) и Android SDK — Gradle подтягивается через ./gradlew.
Структура
shared/src/commonMain/ общий код и UI — весь функционал приложения
├── Particle.kt частица, связь, ячейка сетки, константы
├── Physics.kt шаг симуляции и расчёт сил (порт physics.dart)
├── Simulation.kt состояние: частицы, связи, сетка, resize/reset/tap
├── App.kt экран, холст, кнопки, цикл кадров (порт main.dart + painter.dart)
├── SettingsDialog.kt диалог настроек (порт settings.dart)
└── Theme.kt expect для динамической палитры
shared/src/androidMain/ actual: Material You с Android 12+
shared/src/desktopMain/ actual: палитра по умолчанию + fun main()
androidApp/ Activity, манифест, ресурсы
Модуля два, потому что AGP 9 не разрешает применять com.android.application
и Kotlin Multiplatform к одному модулю.
Соответствие Flutter-версии
| Flutter | Здесь |
|---|---|
CustomPainter + CustomPaint |
Canvas { } из Compose Foundation |
AnimationController + addListener |
withFrameNanos в LaunchedEffect |
setState каждый кадр |
счётчик кадров, который читает только draw-фаза |
dynamic_color |
dynamicLightColorScheme / dynamicDarkColorScheme через expect/actual |
GestureDetector.onTapDown |
pointerInput { detectTapGestures { } } |
showDialog + AlertDialog |
AlertDialog из Material3 |
SystemUiMode.immersiveSticky |
WindowInsetsControllerCompat.hide(systemBars()) |
Физика перенесена один в один, включая порядок обхода ячеек и правила образования связей, так что поведение совпадает с оригиналом. Отличия по существу два:
- Единицы. Симуляция считается в логических пикселях (dp), а холст масштабируется на плотность экрана — иначе на телефоне с density 3 частицы были бы втрое мельче, чем во Flutter.
- Изменение размера окна. Оригинал инициализировал сцену один раз по размеру экрана; здесь при ресайзе окна сетка перестраивается, а частицы сохраняются — на десктопе так осмысленнее.
Состояние
Собирается и запускается на macOS (проверено), APK для Android собирается (проверено); на устройстве Android не запускалось — не было подключённого девайса или эмулятора.