Втрата прогресу — найгірше, що може статися з гравцем. Пройшов 30 рівнів, купив бустери, розблокував персонажів — і після перевстановлення або зміни пристрою нічого нема. Рейтинг у магазині падає, користувач йде. Нещодавно до нас звернувся клієнт: після оновлення всі збереження виявилися битими, 15% активної аудиторії пішло за тиждень. Після впровадження нашої системи відтік скоротився до 2%, а рейтинг у магазині виріс з 3.2 до 4.5 зірок. Ми знаємо, як цього уникнути.
Ми розробляємо систему збереження під ключ для ігор на Unity, Android, iOS та кроссплатформенних проєктах. За 5 років реалізували понад 40 ігор, гарантуючи збереженість даних та безшовний користувацький досвід. Оцінимо ваш проєкт — зв'яжіться з нами, щоб обговорити деталі.
Які дані потрібно зберігати і де?
Прогрес гри включає кілька типів даних з різними вимогами до надійності та швидкості доступу:
- Критичні дані: рівень, валюта, покупки. Повинні синхронізуватися з сервером — ніколи не втрачатися. Зберігаються локально + хмара.
- Ігровий прогрес: пройдені рівні, досягнення, розблоковані предмети. Локально + опціональна синхронізація.
- Користувацькі налаштування: гучність, керування, графіка. Тільки локально — втрата некритична.
- Сесійні дані: поточний рівень, позиція, тимчасові бафи. Тільки в пам'яті — не потребують персистентності.
| Тип даних | Місце зберігання | Частота збереження | Ризик втрати |
|---|---|---|---|
| Критичні | Локально + хмара | Після кожної зміни | Мінімальний |
| Ігровий прогрес | Локально + опціонально хмара | При проходженні рівнів | Низький |
| Налаштування | Локально | За запитом користувача | Приймається |
| Сесійні | Пам'ять | Не зберігаються | Високий (але допустимий) |
Локальне зберігання
Для простих ігор — JSON-файл або SharedPreferences/UserDefaults. Для складного прогресу з безліччю сутностей — SQLite через Room.
@Entity(tableName = "save_data") data class SaveDataEntity( @PrimaryKey val playerId: String, val level: Int, val experience: Long, val coins: Long, val gems: Int, val unlockedLevels: String, // JSON array val inventory: String, // JSON array val achievements: String, // JSON array val settings: String, // JSON object val lastSavedAt: Long, val version: Int = 1 // для міграцій формату ) Для Unity — PlayerPrefs для простих значень, Application.persistentDataPath + бінарний файл для складних структур. BinaryFormatter застарів у сучасних версіях Unity — використовуємо JsonUtility або Newtonsoft.Json + File.WriteAllBytes.
// Unity: збереження через JsonUtility [Serializable] public class SaveData { public int level; public long coins; public List<string> unlockedItems = new List<string>(); public int[] levelStars; // 3 зірки на кожен рівень public long savedAt; } public class SaveSystem : MonoBehaviour { private const string SAVE_FILE = "save.json"; public static void Save(SaveData data) { data.savedAt = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); string json = JsonUtility.ToJson(data); string path = Path.Combine(Application.persistentDataPath, SAVE_FILE); // Спочатку пишемо в temp, потім перейменовуємо — атомарна операція string tempPath = path + ".tmp"; File.WriteAllText(tempPath, json); File.Move(tempPath, path, overwrite: true); } } Запис через temp-файл з подальшим перейменуванням — захист від корумпованого файлу при креші під час запису.
Хмарна синхронізація
Для кроссплатформенних ігор — власний бекенд. Для iOS-only — Game Center + iCloud. Для Android — Google Play Games Services. Для Unity — обгортки над обома.
// Android: Google Play Games Services GamesSignInClient.signIn().addOnCompleteListener { task -> if (task.isSuccessful) { PlayGames.getSnapshotsClient(activity) .open(SNAPSHOT_NAME, true, SnapshotsClient.RESOLUTION_POLICY_MOST_RECENTLY_MODIFIED) .addOnSuccessListener { dataOrConflict -> if (dataOrConflict.isConflict) { resolveConflict(dataOrConflict.conflict) } else { loadFromSnapshot(dataOrConflict.data) } } } } Google Play Games Snapshots API автоматично керує конфліктами при RESOLUTION_POLICY_MOST_RECENTLY_MODIFIED — перемагає більш свіже збереження. Для більшості ігор цього достатньо.
Порівняйте хмарні рішення:
| Платформа | Сервіс | Автоматичне вирішення конфліктів | Ліміт розміру збереження |
|---|---|---|---|
| iOS | CloudKit | Так (останній запис) | 1 MB на запис, 10 MB загальний |
| Android | Google Play Games Snapshots | Так (останній запис або ручне) | 3 MB |
| Кроссплатформа | Власний бекенд | Налаштовується | Необмежений |
Згідно з документацією Apple, CloudKit забезпечує автоматичне вирішення конфліктів на основі часових міток. В одному проєкті впровадження серверної валідації дозволило заощадити понад $10,000 на місяць на поверненнях від чітерів.
Чому важлива міграція формату?
Формат даних змінюється з оновленнями гри. Потрібна міграційна система:
class SaveMigrator { fun migrate(data: SaveDataEntity): SaveDataEntity { var current = data while (current.version < CURRENT_VERSION) { current = when (current.version) { 1 -> migrateV1toV2(current) 2 -> migrateV2toV3(current) else -> throw IllegalStateException("Unknown version: ${current.version}") } } return current } private fun migrateV1toV2(data: SaveDataEntity): SaveDataEntity { // У версії 2 додали daily challenges progress return data.copy( dailyChallenges = "{}", version = 2 ) } } Перевіряємо версію при завантаженні — якщо стара, мігруємо до актуальної та зберігаємо заново.
Як забезпечити захист від чітерства?
Для ігор з монетизацією — хеш для виявлення модифікації файлу:
fun computeChecksum(data: SaveDataEntity): String { val content = "${data.playerId}|${data.coins}|${data.gems}|${data.level}|${SECRET_SALT}" return MessageDigest.getInstance("SHA-256") .digest(content.toByteArray()) .fold("") { str, byte -> str + "%02x".format(byte) } } Серверна валідація — надійніше. Критичні операції (покупка за gems) проходять через сервер, клієнт не може просто записати потрібне значення у файл. В одному проєкті ми знизили кількість чітерів на 95% всього за місяць після впровадження серверної перевірки кожної покупки.
Як вибрати між CloudKit та Google Play Games?
Вибір залежить від платформи та вимог. Якщо гра тільки на iOS — CloudKit та Game Center. Для Android — Google Play Games Snapshots. Для кроссплатформенного проєкту частіше обирають власний бекенд для єдності. Ми допомагаємо визначитися на етапі аудиту — замовте консультацію, щоб отримати оптимальне рішення.
Що входить у розробку системи збереження
Ми надаємо:
- Аналіз вимог до даних та вибір архітектури
- Реалізацію локального сховища (Room, DataStore, CoreData, PlayerPrefs)
- Підключення хмарної синхронізації (iCloud, Google Play Games, власний сервер)
- Механізм міграції формату при оновленнях
- Захист від злому (хеші, серверна валідація)
- Тестування на різних пристроях та версіях ОС
- Документацію та навчання команди
Терміни — від 2 до 4 тижнів залежно від складності. Ми проводимо навантажувальне тестування: симулюємо 1000 одночасних збережень, щоб переконатися у відмовостійкості. Середня окупність інвестицій — 3 місяці за рахунок лояльності користувачів. Зв'яжіться з нами, щоб отримати консультацію та оцінку вашого проєкту.







