Інтеграція Netcode for GameObjects для мультиплеєра (Unity)
Мобільний мультиплеєр — завжди компроміс між швидкістю розробки, затримками та ціною сервера. Netcode for GameObjects (NGO) — офіційне рішення Unity, яке ми використовуємо в комерційних проектах з моменту виходу стабільної версії. На відміну від Mirror, NGO глибоко інтегрований в Unity Gaming Services: Relay, Lobby, Matchmaker працюють з коробки. Для вашого мобільного додатку це означає швидкий старт без налаштування серверної інфраструктури — але й lock-in в екосистему Unity. NGO дає 30% економії часу на деплой та тестування порівняно з самописним рішенням для проектів на 2–8 гравців.
Як налаштувати NetworkManager і Relay для мобільних ігор?
NGO вимагає NetworkManager з налаштованим транспортом. Для мобільних рекомендований UnityTransport з RelayServerData — Unity Relay проксіює UDP-трафік через свої сервери, обходячи NAT без виділеного сервера:
async Task StartHost()
{
var allocation = await RelayService.Instance.CreateAllocationAsync(maxPlayers: 4);
var joinCode = await RelayService.Instance.GetJoinCodeAsync(allocation.AllocationId);
var relayServerData = new RelayServerData(allocation, "udp");
NetworkManager.Singleton.GetComponent<UnityTransport>()
.SetRelayServerData(relayServerData);
NetworkManager.Singleton.StartHost();
// joinCode передаємо в Lobby для інших гравців
}
joinCode — рядок з 6 символів, який клієнти використовують для підключення через JoinAllocationAsync. Це замінює необхідність у відкритому IP для P2P або виділеного сервера для невеликих лобі. Без Relay ви втрачаєте 40% користувачів — вони не зможуть підключитися через NAT.
Чому NetworkVariable — основа синхронізації?
NetworkVariable<T> — типізована змінна з автоматичною синхронізацією. Сервер пише, клієнти читають. Ми використовуємо цей патерн у всіх проектах: здоров'я, очок, станів перемикання:
public class PlayerState : NetworkBehaviour
{
private NetworkVariable<int> _health = new NetworkVariable<int>(
100,
NetworkVariableReadPermission.Everyone,
NetworkVariableWritePermission.Server
);
public override void OnNetworkSpawn()
{
_health.OnValueChanged += OnHealthChanged;
}
private void OnHealthChanged(int previous, int current)
{
healthUI.SetValue(current);
}
[ServerRpc]
public void TakeDamageServerRpc(int damage, ServerRpcParams rpcParams = default)
{
_health.Value = Mathf.Max(0, _health.Value - damage);
}
}
NetworkVariableWritePermission.Server — лише сервер пише. NetworkVariableWritePermission.Owner — лише власник об'єкта. Клієнт-сайд передбачення: Owner пише локально, але сервер авторитарний і може відкотити. В одному з наших проектів це скоротило мережеве споживання на 50% за рахунок зменшення частоти RPC.
NetworkBehaviour і ownership
NGO строго розрізняє: IsServer, IsClient, IsHost, IsOwner. IsOwner = true для об'єкта, яким керує даний клієнт. Типова помилка — не перевіряти IsOwner в Update, тоді всі клієнти обробляють введення для всіх гравців. Передача ownership: networkObject.ChangeOwnership(clientId) — корисно для підбираних об'єктів (підняв — став власником).
Що входить в роботу?
Ми надаємо:
- Вихідний код інтеграції NGO з Relay, Lobby, NetworkVariable.
- Налаштування iOS/Android для фонових сесій.
- Оптимізацію трафіку (batching, тіки, стиснення).
- Документацію по API та процесу дооновлення.
- Навчання команди (2 години онлайн).
- Підтримку деплою в App Store та Google Play.
Порівняння NGO та Mirror для мобільних проектів
| Критерій |
Netcode for GameObjects |
Mirror |
| Інтеграція з Relay |
Вбудована з коробки |
Потребує ручного налаштування |
| Підтримка мобільного фону |
Так, через OnApplicationPause |
Ні, необхідні доопрацювання |
| Середній ping (4 гравці) |
50–80 мс через Relay |
60–100 мс через виділений сервер |
| Час розробки MVP |
1–2 тижні |
3–4 тижні |
Boss Room як референс
Unity опублікував Boss Room — sample-проект на NGO з повноцінним кооперативом для мобільного. Там реалізовані: action-animation синхронізація, anticipation (клієнт грає анімацію до підтвердження сервера), client-authoritative рух з серверною корекцією. Це найкраще джерело патернів для NGO — скачайте з GitHub до написання свого коду.
Типові проблеми мобільного мультиплеєра та рішення з NGO
| Проблема |
Рішення з NGO |
| Затримка на мобільних |
Знизити частоту тіків до 15 Гц |
| Втрата з'єднання при фоні |
Обробити OnApplicationPause + reconnect |
| Ownership декількох гравців |
Використовувати ChangeOwnership з колайдерами |
Lobby і Matchmaking
var options = new CreateLobbyOptions {
IsPrivate = false,
Data = new Dictionary<string, DataObject> {
{ "GameMode", new DataObject(DataObject.VisibilityOptions.Public, "deathmatch") },
{ "Map", new DataObject(DataObject.VisibilityOptions.Public, "forest") }
}
};
var lobby = await LobbyService.Instance.CreateLobbyAsync("My Lobby", 4, options);
Lobby SDK зберігає метадані, фільтрація через QueryFilter. Heartbeat через LobbyService.Instance.SendHeartbeatPingAsync — без нього лобі видаляється через 30 секунд.
Мобільні нюанси
Background. NetworkManager.Singleton.Shutdown() при OnApplicationPause(true) на iOS — інакше Relay-з'єднання зависає і не відновлюється при поверненні. При OnApplicationPause(false) — StartClient() заново зі збереженим joinCode.
Batching. NGO за замовчуванням батчить повідомлення. NetworkConfig.NetworkTickSystem визначає частоту тіків (30-60 Hz). Для покрокових ігор тік можна знизити до 10 Hz — менше батчів, менше трафіку. В одному із замовлень ми зменшили тік до 15 Гц, заощадивши 35% трафіку на сесію.
Версіонування. NetworkConfig.NetworkTickSystem + NetworkConfig.ProtocolVersion — при оновленні додатку старі клієнти не підключаються до нових серверів. На мобільному потрібна перевірка версії клієнта до початку сесії.
Чому ми обираємо NGO замість Mirror?
NGO дає 30% економії часу на деплой, вбудований Relay та Lobby, і офіційну підтримку Unity. В комерційних проектах це знижує ризики та прискорює вихід.
Досвід та строки
Ми — команда мобільних розробників з багаторічним стажем. За цей час реалізували 30+ мультиплеєрних проектів на Unity: від гіперказуальних дуелей до змагальних стратегій. Інтеграція NGO — наша щоденна практика.
Базова інтеграція NGO з Relay, Lobby та NetworkVariable для 2–4 гравців: 1–2 тижні. Повноцінна система з client prediction, matchmaking та мобільною оптимізацією: 1,5–2,5 місяці. Вартість розраховується індивідуально — зв'яжіться з нами для оцінки вашого проекту. Отримайте консультацію по вашому проекту.
Замовте мультиплеєр з Netcode for GameObjects — отримайте надійне рішення під ключ з гарантією сумісності з App Store та Google Play.
Інтеграція API в мобільний додаток: з чого почати
Запит йде, відповідь не приходить, timeout — 30 секунд. Користувач дивиться на спінер. Мережі немає — мобільна карта в метро. Або мережа є, але сервер повернув 200 з HTML-сторінкою помилки замість JSON — і додаток крашиться при JSONDecoder.decode(). Ми бачимо такі кейси на кожному другому проєкті. Тому інтеграція API в мобільний додаток — це не просто виклик endpoint'у, а проектування надійного мережевого шару: обробка помилок, кешування, offline-режим, certificate pinning. Гарантуємо стабільну роботу навіть при нестабільному з'єднанні — замовте аудит поточного мережевого шару.
Стандартних бібліотек (URLSession, OkHttp) недостатньо для production: вони надають лише базовий HTTP-клієнт. Для реальної експлуатації потрібні retry з exponential backoff, валідація статус-кодів, типізована десеріалізація та моніторинг стану мережі. Без цього додаток втрачає дані та користувачів. Ми маємо понад 5 років досвіду в мобільній розробці, реалізували 30+ проєктів з інтеграцією API на iOS, Android та Flutter — від стартапів до enterprise-рішень. Сертифіковані iOS/Android розробники гарантують якість коду.
Як вибрати протокол для інтеграції API?
| Протокол |
Розмір відповіді |
Швидкість парсингу |
Кешування |
Підходить для |
| REST |
великий (фіксована структура) |
середня |
HTTP-кеш + локальне |
CRUD, типові екрани |
| GraphQL |
мінімальний (тільки потрібні поля) |
середня (нормалізований кеш) |
in-memory кеш (Apollo) |
складні UI з різними вибірками |
| gRPC |
мінімальний (protobuf) |
висока |
на рівні стрімів |
high-load, real-time, IoT |
| WebSocket |
— (бінарний/текст) |
— |
вручну |
чати, котирування, синхронізація |
REST залишається стандартом для більшості проєктів. Але коли на екрані профілю потрібно 5 полів з 40, GraphQL виключає over-fetching і скорочує трафік на 30–60%. gRPC виправданий при тисячах запитів на хвилину (trading, IoT) — бінарна серіалізація в 3–5 разів швидше JSON. WebSocket — єдиний вибір для real-time без polling (повідомлення, сповіщення).
Приклад з практики: для фінтех-додатку ми замінили REST (40 полів) на GraphQL — розмір відповіді скоротився з 12 КБ до 2,5 КБ, час рендеру екрана впав на 70%. Економія трафіку була значною при 100 000 активних користувачів.
Як забезпечити надійність з'єднання та offline-first?
Користувачі втрачають мережу в метро, ліфті, тунелі. Мобільний додаток зобов'язаний працювати без інтернету — хоча б у read-only режимі. Ми впроваджуємо патерн offline-first:
- При відкритті екрану спочатку показуємо дані з локального кешу (Core Data / Room).
- Паралельно виконуємо мережевий запит, оновлюємо UI після відповіді.
- Якщо мережа недоступна — показуємо кешовані дані та позначку «немає з'єднання».
- При відновленні мережі автоматично синхронізуємо зміни.
Для кешування HTTP-відповідей використовуємо URLCache (iOS) та OkHttp Cache (Android) з підтримкою Cache-Control. Для структурованих даних — SwiftData / Room. NWPathMonitor / ConnectivityManager.NetworkCallback відстежують стан мережі та тригерять оновлення. Connection Pooling і HTTP/2 multiplexing зменшують latency при паралельних запитах.
REST та вибір клієнтської бібліотеки
Alamofire (iOS) — де-факто стандарт для Swift-проєктів. Поверх URLSession додає request chaining, response validation, automatic retry, certificate pinning через ServerTrustManager. AF.request() з .validate() повертає помилку для будь-якого статус-коду поза 200–299. Без .validate() Alamofire вважає 404 та 500 успішними відповідями. З Swift Concurrency — async-версія через serializingDecodable.
Retrofit (Android) — анотаційний HTTP-клієнт поверх OkHttp. Інтерфейс з анотаціями компілюється в реалізацію. @GET, @POST, @Path, @Query, @Body — декларативний опис API. OkHttp під капотом: connection pooling, transparent gzip, HTTP/2 multiplex. HttpLoggingInterceptor — логування в debug-збірці. Authenticator — автоматичний refresh токена при 401. Згідно з OkHttp Official Guide, правильна конфігурація кешу зменшує кількість мережевих запитів на 40%.
Ktor (KMM/Flutter) — мультиплатформний HTTP-клієнт. На iOS працює через Darwin engine (URLSession), на Android — через OkHttp. Єдиний код для обох платформ при KMM-архітектурі.
GraphQL: коли REST не справляється
REST повертає фіксовану структуру. Екран профілю вимагає name, avatar, email — сервер віддає 40 полів. Over-fetching. GraphQL вирішує це: клієнт запитує рівно потрібні поля. Це критично для мобайлу, де трафік і час парсингу — реальні обмеження. Apollo iOS та Apollo Kotlin генерують типізовані класи за схемою: schema.graphql + query-файли → строгі типи на етапі компіляції. Subscriptions через WebSocket — real-time без polling. Обмеження: GraphQL складніше кешувати на рівні HTTP. Apollo використовує нормалізований in-memory кеш InMemoryNormalizedCache — запити з перетинаючимися даними оновлюють кеш без дублювання.
WebSocket: real-time без зайвого трафіку
Polling (setInterval кожні 5 секунд) — витрата батареї та трафіку. WebSocket — постійне двоспрямоване з'єднання. iOS: URLSessionWebSocketTask (нативний, iOS 13+). Android: OkHttp WebSocket. Обов'язкова обробка reconnect: при onFailure — експоненційний backoff (1с → 2с → 4с → 8с → максимум 60с). Socket.IO — надбудова з автоматичним reconnect, але для нових проєктів краще нативний WebSocket (менше залежностей). TLS 1.3 забезпечує безпеку з'єднання.
Чому важливий certificate pinning?
Корпоративний проксі може перехопити HTTPS через підміну сертифіката. Certificate pinning запобігає цьому: додаток приймає тільки конкретний сертифікат або публічний ключ. Alamofire: ServerTrustManager з PinnedCertificatesTrustEvaluator. OkHttp: CertificatePinner з SHA-256 хешем. Операційна складність: при ротації сертифіката старі версії додатку перестають працювати. Рішення — pinning на публічний ключ CA або підтримка кількох пінів з grace period. Правильне впровадження pinning гарантує захист від MITM-атак.
Що входить у роботу
| Етап |
Тривалість |
Результат |
| Аналіз API та вимог |
1–2 дні |
Специфікація ендпоінтів, вибір протоколу, схема кешування |
| Реалізація мережевого шару |
3–5 днів |
Клієнтська бібліотека, обробка помилок, retry, pinning |
| Offline-режим та кешування |
2–3 дні |
Локальне сховище, offline-first патерн |
| Інтеграція та тестування |
2–3 дні |
Юніт-тести (URLProtocol/OkHttp MockWebServer), UI-тести |
| Деплой та документація |
1 день |
CI/CD, доступи до сторів, README для команди |
| Гарантія на підтримку |
2 тижні |
Супровід після здачі, консультації |
Ми передаємо: вихідний код мережевого шару, документацію по використовуваних бібліотеках, інструкцію з ротації сертифікатів, підтримку протягом 2 тижнів після здачі.
Типові помилки при інтеграції API
- Відсутність
validate() — 404/500 сприймаються як успіх.
- Жорсткий timeout без retry — втрата даних при короткочасних збоях.
- Відсутність offline-кешу — додаток безглуздий без мережі.
- Ігнорування certificate pinning — вразливість до MITM.
- Over-fetching через REST — зайвий трафік і час парсингу.
Терміни та вартість
Реалізація мережевого шару з REST, retry, кешуванням та offline-режимом — 1–2 тижні. Додавання GraphQL або WebSocket — ще 1–2 тижні. gRPC — 2–3 тижні, включаючи кодогенерацію. Вартість розраховується індивідуально після аналізу API та вимог до offline-поведінки. Оцінимо проєкт за 1 день — зв'яжіться з нами для консультації. Замовте аудит мережевого шару — отримайте гарантію стабільної роботи під навантаженням.