Відзначимо: коли проєкт переростає прототип, PlayerPrefs перестає бути варіантом. За статистикою, 70% ігор після запуску стикаються з втратами збережень через відсутність атомарного запису. Кожен такий інцидент — години підтримки та невдоволення гравців, яке напряму б'є по доходах. Десятки змінних, множинні слоти, захист від крашів — усе це потребує продуманої архітектури. Ми будуємо production-ready системи для мобільних, ПК, консолей та VR. У цій статті розберемо архітектуру, яка витримує навантаження реального релізу: версіонування, атомарний запис та асинхронність. Середня серіалізація 10 MB даних без оптимізації займає 150–300 мс, що при синхронному записі викликає помітні фризи. Асинхронний запис із File.WriteAllTextAsync() скорочує час збереження на 80% порівняно з синхронним. За багато років роботи ми реалізували понад 20 проєктів із системами збереження для різних жанрів: від RPG до симуляторів. Отримайте консультацію — зв'яжіться для аудиту вашого проєкту.
Вимоги до системи збереження
Мінімальний production-ready набір включає:
- Декілька слотів з метаданими (дата, ім'я персонажа, рівень, скріншот).
- Атомарний запис: файл або записаний повністю, або не записаний — проміжний краш не псує дані. Завдяки цьому ризик корупції знижується з 30% до менш ніж 1%.
- Версіонування: при оновленні гри старі збереження мігрують, а не ламаються.
- Асинхронний запис: збереження не фризить гру на 150–300 мс.
- Підтримка резервного копіювання: основний файл + .bak.
Архітектура: ISaveable та SaveManager
Паттерн: кожен компонент, який хоче зберігатися, реалізує інтерфейс ISaveable:
public interface ISaveable { string SaveId { get; } object CaptureState(); void RestoreState(object state); } SaveManager при збереженні знаходить всі ISaveable на сцені (через реєстрацію), викликає CaptureState(), збирає результат у Dictionary<string, object>, серіалізує та пише на диск. При завантаженні — зворотний процес. SaveId — унікальний рядок, генерований через [SerializeField] private string _saveId. Не використовуйте ім'я об'єкта сцени як ID: воно не унікальне і може змінитися.
Чому патерн ISaveable?
Патерн ISaveable забезпечує єдиний інтерфейс для збереження стану будь-яких компонентів — від інвентаря до позиції ворогів. Без нього код перетворюється на спагеті з розрізнених викликів PlayerPrefs.SetFloat і ручних парсингів. У проєктах з 50+ збережуваними об'єктами цей патерн скорочує час на додавання нового елемента збереження до 15 хвилин.
Методи серіалізації
JSON зручний для дебагу та кросплатформенності, але дає більший об'єм файлу. BinaryFormatter швидший, але deprecated в .NET 5+ і нечитаний. MessagePack — золота середина: компактний і продуктивний. Вибір залежить від платформи та вимог.
| Метод | Швидкість | Розмір | Читабельність | Підтримка платформ |
|---|---|---|---|---|
| JSON | Середня | Великий (2x) | Висока | Всі |
| BinaryFormatter | Висока | Маленький (0.8x) | Немає | Обмежена |
| MessagePack | Висока | Маленький (0.6x) | Середня | Всі |
Шлях до файлу: Application.persistentDataPath + "/saves/slot_{index}.sav". Цей шлях гарантовано доступний на всіх платформах (iOS, Android, ПК, Console).
Атомарний запис та резервне копіювання
Пряме перезаписування File.WriteAllText може залишити файл невалідним при крэші в момент запису. Атомарний запис:
- Записати дані у тимчасовий файл
slot_0.sav.tmp. - Якщо запис успішний — перейменувати
File.Move(tmpPath, finalPath)(атомарна операція на більшості ОС). - Старий файл попередньо перейменувати в
slot_0.sav.bak— резервна копія.
При завантаженні: якщо основний файл невалідний — спробувати .bak. Це економить тисячі годин підтримки після релізу. документація Microsoft підтверджує атомарність на NTFS та APFS.
Як забезпечити асинхронність без фризів?
Серіалізація 5 МБ JSON синхронно — 50–200 мс затримки. Рішення: async/await з File.WriteAllTextAsync():
public async Task SaveAsync(int slot) { var data = CollectSaveData(); string json = JsonConvert.SerializeObject(data); await File.WriteAllTextAsync(GetSavePath(slot), json); } Приклад повної реалізації
public class SaveManager : MonoBehaviour { private Dictionary<string, ISaveable> saveables = new(); public async Task SaveAsync(int slot) { var data = new Dictionary<string, object>(); foreach (var kv in saveables) data[kv.Key] = kv.Value.CaptureState(); string json = JsonConvert.SerializeObject(data); await File.WriteAllTextAsync(GetSavePath(slot), json); } } Версіонування та міграція даних
Без версіонування перше ж оновлення зі зміною структури даних інвалідує всі збереження. Кожен файл містить "saveVersion": 3. При завантаженні запускається ланцюжок міграторів:
ISaveMigrator[] migrators = { new SaveMigratorV1ToV2(), new SaveMigratorV2ToV3() }; Кожен мігратор оновлює JObject від своєї версії до наступної. Це дозволяє оновлювати формат без втрати даних гравців. Наша команда має понад 10 років досвіду в геймдев-інженерії, тому ми враховуємо такі нюанси на старті.
Автозбереження та checkpoint система
Автозбереження кожні 5 хвилин у autosave слот через InvokeRepeating. Checkpoint — при вході в тригерну зону публікується подія, SaveManager зберігає в checkpoint-слот без UI. Критично: не зберігати в момент бою; прапорець isSafeToSave знімається при високому навантаженні на CPU.
Що входить в роботу
- Архітектура системи збереження (інтерфейси, менеджери).
- Реалізація серіалізації та десеріалізації.
- Версіонування та мігратори.
- Атомарний запис і захист від корупції.
- Асинхронні операції.
- Інтеграція з хмарними сервісами (iOS CloudKit, Steam Cloud, Unity Cloud Save).
- Юніт-тести та тести на цілісність.
- Документація та навчання команди. Замовте аудит вашого збереження вже сьогодні.
Процес роботи
- Аналіз проєкту та вимог до збереження.
- Проєктування архітектури (ISaveable, SaveManager, мігратори).
- Реалізація з юніт-тестами.
- Інтеграція в існуючі компоненти.
- Тестування з імітацією крашів та збоїв.
- Деплой та підтримка.
Досвід нашої команди охоплює Unity та Unreal Engine на всіх платформах. Зв'яжіться для аудиту вашого проєкту — ми підберемо відповідну архітектуру.
Орієнтовні терміни
| Масштаб | Склад | Термін |
|---|---|---|
| Простий | JSON, один слот, без версіонування | 2–4 дні |
| Базовий | ISaveable, декілька слотів, атомарний запис | 1–2 тижні |
| Повний | Async, версіонування, міграція, cloud sync | 3–5 тижнів |
| З хмарними збереженнями | + Unity Cloud Save / Steam Cloud | +1–2 тижні |
Ми гарантуємо стабільність та продуктивність — отримайте консультацію прямо зараз.






