Как оптимизировать физический движок для мобильных игр?
Мы часто сталкиваемся с ситуацией: игра с достоверной физикой на Unity падает до 15 FPS на Snapdragon 680 через минуту после запуска. Полноценная симуляция PhysX или Bullet в 120 Гц — непозволительная роскошь для мобильного CPU. Поэтому наш подход — искать компромисс между достоверностью и производительностью для каждого жанра. Свяжитесь с нами — оценим ваш проект за 2 дня и предложим оптимальную архитектуру.
Фиксированный timestep и его цена
Unity обновляет физику в FixedUpdate с интервалом Time.fixedDeltaTime (по умолчанию 50 Гц). На мобильном устройстве, работающем в 30 FPS, это значит два физических шага на кадр. Если игра идёт в 20 FPS из-за тепловой защиты, Unity делает 2-3 шага PhysX за один отрисованный кадр — CPU нагрузка растёт нелинейно. Согласно документации Unity, FixedUpdate вызывается с фиксированным интервалом, но на слабых устройствах это может приводить к просадкам.
Оптимальная стратегия: снижать Fixed Timestep до 0.033 (30 Гц) для мобильных билдов и компенсировать это более точными коллайдерами. Для игр, где физика не критична для геймплея (паззлы, гиперкежуал), можно опустить до 0.05 (20 Гц) и интерполировать позиции объектов визуально через Rigidbody.interpolation = RigidbodyInterpolation.Interpolate. Более 5 лет опыта в мобильном геймдеве — мы перебрали десятки конфигураций и добились снижения CPU нагрузки на физику до 40%.
Когда PhysX избыточен
Для 2D-игр на Unity встроенная физика Box2D (через Rigidbody2D, Physics2D) значительно легче PhysX. Но даже Box2D на 200+ динамических объектах начинает давить на CPU. В Godot 4 аналогично — RigidBody2D + GodotPhysics2D эффективнее, чем 3D-физика для плоских игр.
Для гиперкежуал и аркадных механик часто выгоднее полностью отказаться от движкового физического движка и написать детерминированную физику вручную:
// Упрощённая физика прыжка без Rigidbody void Update() { if (isGrounded && Input.GetTouch(0).phase == TouchPhase.Began) velocity.y = jumpForce; velocity.y -= gravity * Time.deltaTime; transform.position += velocity * Time.deltaTime; if (transform.position.y <= groundLevel) { transform.position = new Vector3(transform.position.x, groundLevel, 0); velocity.y = 0; isGrounded = true; } } Детерминированная физика предсказуема, дебажится в одно касание и работает одинаково на любом устройстве. Для мультиплеерных игр это ещё и гарантия синхронизации состояний.
Как написать детерминированную физику: пошаговое руководство
- Определите необходимые свойства: гравитация, скорость, ускорение.
- В каждом кадре обновляйте позицию через
transform.position += velocity * Time.deltaTime. - Обрабатывайте коллизии простыми проверками (например, по границам экрана).
- Для взаимодействия объектов используйте минимальные вычисления без физического движка.
Такой подход позволяет добиться 60 FPS на бюджетных устройствах даже с сотней объектов.
Почему кастомная физика иногда выгоднее?
Взаимодействие объектов: где обычно ломается
Стекирование объектов PhysX плохо симулирует стопки из 10+ динамических объектов на мобильном железе — начинается джиттер и объекты «проваливаются» сквозь друг друга. Решение: Rigidbody.maxDepenetrationVelocity снижать до 1-3 м/с (вместо default 10), Physics.defaultSolverIterations до 4-6 (default 6), Physics.defaultSolverVelocityIterations до 1.
Thin colliders и туннелирование Быстрые объекты — пули, снаряды — на низком FPS за один шаг могут пролететь сквозь тонкую стену. Rigidbody.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic решает проблему, но вдвое дороже по CPU. Альтернатива: для снарядов использовать raycast вместо физического тела — Physics.SphereCast с радиусом снаряда от предыдущей позиции до текущей.
Производительность на разных устройствах
Реальная картина из профайлера (Unity Profiler + Android Profiler) в проекте с 3D-аркадой (80 физических объектов, Snapdragon 665):
| Конфигурация | Fixed Timestep | CPU на физику | FPS |
|---|---|---|---|
| Default PhysX | 50 Гц | 4.2 мс/кадр | 38 |
| Reduced iterations | 30 Гц | 2.1 мс/кадр | 56 |
| Кастомная физика | N/A | 0.6 мс/кадр | 60 |
Кастомная физика — для конкретного жанра, а не универсальное решение. Но когда игровая механика это позволяет, выигрыш очевиден. Мы спроектировали более 50 мобильных игр с разными физическими подходами — от аркад до симуляторов.
Сравнение популярных движков:
| Движок | Платформа | Производительность | Детерминизм | Рекомендация |
|---|---|---|---|---|
| Box2D | 2D | Средняя | Да | Для 2D-игр до 200 объектов |
| PhysX | 3D | Высокая | Нет | Для 3D с мощными устройствами |
| Кастомная физика | Любая | Максимальная | Да | Для гиперкежуал и мультиплеера |
Физика в React Native и Flutter играх
Для React Native игра пишется либо на Godot с экспортом в Web/Android, либо через движок на JavaScript (Phaser.js через WebView). Phaser использует Matter.js для 2D-физики — он легче Box2D по потреблению памяти, но уступает по точности. Matter.Runner.run() с fps: 30 на большинстве Android-бюджетников достаточно.
Для Flutter + flame: forge2d (порт Box2D на Dart) даёт полноценную 2D-физику. World.stepDt вызывается в game.update(dt), частота обновлений контролируется игровым лупом flame. Критично: forge2d работает в метрах, а flame — в пикселях. Коэффициент пересчёта (worldScale) нужно задавать один раз и придерживаться его везде.
Когда стоит использовать кастомную физику
Кастомная физика оправдана, если: игра содержит уникальные механики (резиновые объекты, деформации), требуется детерминизм для мультиплеера, или стандартные движки не обеспечивают нужный FPS на целевых устройствах. В остальных случаях достаточно настройки существующего движка.Что входит в работу
- Анализ механик и профилирование целевых устройств
- Выбор физического движка или проектирование кастомного решения
- Разработка и настройка физических взаимодействий
- Оптимизация под низкопроизводительные устройства (троттлинг, теплозащита)
- Интеграция с аналитикой и crash-репортами
- Документация по конфигам и поддержка при релизе
Процесс работы
Начинаем с профилирования целевых устройств — бюджетный Android и топовый iPhone дают разную картину. Выбираем физический движок или кастомную реализацию исходя из жанра, количества объектов и целевого FPS. Пишем физические взаимодействия, профилируем в реальных условиях (throttle mode, без зарядки), итерируем.
Типичные сроки: базовые физические взаимодействия — 1-2 недели, сложные системы (разрушаемые объекты, гибкие тела, fluid simulation) — 3-6 недель. Стоимость рассчитывается индивидуально после анализа механик. Получите консультацию по архитектуре физики вашей игры — свяжитесь с нами.







