Розробка ігор на Unity
Проект уже на половині шляху, сцени не компілюються у білд без помилок компіляції, кеш AssetBundle розпух до 4 ГБ, а на цільовому Android-пристрої URP рендерить 8 FPS замість 30. Звична картина. Unity — потужний інструмент, який при неправильній архітектурі перетворюється на джерело технічного боргу швидше, ніж ви встигнете дописати геймплей.
Де зазвичай ломаються Unity-проекти
Найчастіша проблема — неправильне управління життєвим циклом об'єктів. MonoBehaviour.Update() на 400 активних об'єктах, кожен з яких дергає GetComponent<Rigidbody>() кожен кадр, — це не архітектура, це катастрофа. На ПК це непомітно. На iOS A14 це 12 мс оверхеду тільки на рефлексію.
Другий класичний граль — AddressableAssets без стратегії вивантаження. Проект підгружає локації через Addressables.LoadAssetAsync, але забуває викликати Addressables.Release(). Через годину ігрової сесії RSS процесу вирастає з 800 МБ до 2.4 ГБ, і iOS вбиває додаток. Це не баг Unity — це баг архітектури.
Третій біль — змішування логіки в сцені та ScriptableObject. Команда починає з MonoBehaviour-синглтонів, потім переходить на ScriptableObject-based EventSystem, але в результаті система подій живе в трьох місцях одночасно. Кожен новий розробник додає шар поверх, і через пів року ніхто не знає, звідки прилітає OnPlayerDied.
Менш очевидна, але регулярна проблема: Physics.Raycast в Update() без LayerMask. Кожен виклик перевіряє всі колайдери сцени. При 50 агентах та складній геометрії це 1-2 мс на кадр тільки на фізику.
Як ми будуємо Unity-проекти
Архітектура та стек
Основа — розділення на три шари: GameplayCore (чистої C# логіки без залежностей від Unity API), UnityGlue (MonoBehaviour-обертки), та Infrastructure (сервіси: збереження, аналітика, мережа). Це дозволяє тестувати геймплей без запуску редактора через NUnit + Unity Test Framework.
Вибираємо рендер-пайплайн під платформу:
| Платформа | Пайплайн | Причина |
|---|---|---|
| Mobile (iOS/Android) | URP | Batching, SRP Batcher, низький оверхед |
| ПК / Console | URP або HDRP | HDRP — тільки якщо потрібен AAA-рендер |
| WebGL | URP | Built-in застарів, HDRP не підтримується |
| 2D проект | URP 2D | Tilemap, Sprite Atlas, 2D Lighting |
Шейдери пишемо через ShaderGraph, де потрібна візуальна ітерація з художником. Продуктивні низькорівневі ефекти — вручну на HLSL з Custom Function Node. Amplify Shader Editor використовуємо тільки якщо проект уже на ньому.
Оптимізація draw calls
На мобільних проектах стандартна ціль — не більше 100-150 draw calls на кадр. Досягається через:
- GPU Instancing на повторюваній геометрії (дерева, пропси). MaterialPropertyBlock для per-instance даних без розриву батча.
- SRP Batcher — працює автоматично з URP, але потребує, щоб усі шейдери були SRP-сумісні. Один non-compatible матеріал рве весь батч.
- Sprite Atlas для UI — критично. UI Canvas з Overlay режимом та 60+ окремими спрайтами дає 60+ draw calls тільки на інтерфейс.
- Occlusion Culling для 3D сцен — запікуємо через Window → Rendering → Occlusion Culling. На рівнях з непрозорою геометрією знижує draw calls на 40-60%.
Профілюємо через Unity Profiler + Frame Debugger + RenderDoc (для детального аналізу GPU). На Android додатково — Android GPU Inspector для Mali/Adreno.
Багатопоточність та ECS
Для проектів з великою кількістю агентів або симуляцій розглядаємо DOTS (Unity ECS + Burst Compiler + Jobs System). Burst компілює C# до нативного SIMD-коду — на задачах вроде pathfinding для 1000 агентів це різниця між 16 мс та 0.8 мс на основному потоці.
Для звичайних проектів без DOTS — UniTask замість корутин. Корутини працюють на MainThread та не скасовуються коректно при знищенні об'єкта. UniTask з CancellationToken вирішує обидві проблеми.
Мультиплеєр
Для реального часу: Photon Fusion 2 (server-authoritative, rollback netcode) або Mirror (self-hosted, відкритий вихідний код). Вибір залежить від вимог до latency та бюджету на інфраструктуру. Для пошагових та асинхронних взаємодій — PlayFab CloudScript + Azure Functions.
Збереження та хмарна синхронізація — Firebase Realtime Database для простих випадків, PlayFab для повноцінного game backend (лідерборди, матчмейкинг, економіка).
Як виглядає процес роботи
Пре-продакшн (1-2 тижні). Розбираємо ТЗ, визначаємо цільові платформи та технічні обмеження. Створюємо вертикальний срез — мінімально робочу механіку в ізоляції. Це важливіше повного дизайн-документа: краще потратити тиждень на прототип, ніж три місяці на розробку механіки, яка не працює на цільовому залізі.
Продакшн. Спринти по 1-2 тижні. Кожен спринт закінчується робочим білдом. Використовуємо Git з LFS для ассетів, Jira або Linear для задач. Code review обов'язковий — особливо на системах, які торкнуться кількох сцен.
Тестування. Unit-тесты на геймплейну логіку (Unity Test Framework, Play Mode). Інтеграційні тесты через Playwright для WebGL. Ручне тестування на реальних пристроях — симулятор iOS не відтворює реальне споживання пам'яті.
Запуск. Автоматичні білди через Unity Cloud Build або GitHub Actions з fastlane для iOS. Android — Google Play Internal Testing, iOS — TestFlight.
Терміни по типу проекту
| Тип проекту | Масштаб | Орієнтовні терміни |
|---|---|---|
| Гіпер-казуальна гра | 1-3 механіки, без бекенду | 2-4 тижні |
| Казуальна мобільна | Прогресія, монетизація, хмара | 2-4 місяці |
| Мідкор мобільна | Мета-геймплей, PvP, економіка | 4-8 місяців |
| ПК інді | Одиночна кампанія | 3-9 місяців |
| ПК мультиплеєр | Мережа, матчмейкинг, античіт | 6-18 місяців |
Вартість розраховується індивідуально після аналізу технічного завдання та цільових платформ.
Типові помилки при запуску Unity-проекту
Ігнорувати Profiler до полірування. "Сначалу зробимо, потім оптимізуємо" працює доти, поки не з'ясується, що архітектурне рішення, прийняте в перший місяць, не піддається оптимізації без переписування половини гри.
Зберігати всі ассети в Resources/. Папка Resources завантажується в пам'ять при старті додатку цілком. 500 МБ текстур у Resources — це 500 МБ RAM до запуску першої сцени. Addressables вирішують це, але потребують планування з самого початку.
Один величезний Canvas для всього UI. Unity перерисовує весь Canvas при зміні будь-якого дочірнього елемента. Розбивайте UI на статичні та динамічні Canvas-компоненти.
Фізика на тригерах замість розрахунків. OnTriggerEnter надійний при низьких швидкостях. Куля, яка летить 200 одиниць/сек, проходить крізь тонкі колайдери між кадрами. Для таких випадків потрібен Physics.SphereCast або Rigidbody з Continuous Collision Detection.





