Ми розробляємо системи досягнень (ачівок) та лідербордів — це частина нашої лідерборд розробка. На старті здається, що достатньо прапора в базі та перевірки умови, але на практиці через півроку вилазять граблі: розсинхрон лічильників після перевстановлення гри, неможливість видати ретроактивні досягнення, конфлікти в багатопоточних середовищах. Досвід 10+ років і 50+ реалізованих проектів дозволяють нам обходити ці проблеми на етапі архітектури. Наші рішення дозволяють замовникам економити до 30% бюджету на розробці завдяки готовим модулям. Ми гарантуємо якість інтеграції та підтримку після запуску.
Чому досягнення складніші, ніж здається?
На старті проекту досягнення виглядають просто: прапор у базі, перевірка умови, запис. На практиці через півроку розробки виявляється наступне:
Стан лічильників розсинхронізовано. Досягнення «убий 100 гоблінів» вимагає персистентного лічильника, який оновлюється при кожному вбивстві. Якщо гравець перевстановив гру, лічильник скинувся — досягнення вже не отримати, хоча в Google Play / Game Center воно позначене як виконане. Це класична проблема dual-state: локальний стан і стан на платформі розходяться.
Ретроактивні досягнення. Команда додає нове досягнення через три місяці після запуску. Гравці, які вже виконали умову, не отримують його автоматично. Потрібна процедура бекфілу — перерахунок за історичною статистикою гравця. Якщо статистика не зберігалася — бекфіл неможливий, гравці зляться.
Thread-safety лічильників. У багатопоточному середовищі (Unity з Jobs System, серверна логіка) одночасне інкрементування лічильника без атомарних операцій дає невірні значення. Кілька івентів одночасно — лічильник стрибає через значення. У 90% випадків ми бачимо цю проблему на етапі навантажувального тестування.
Архітектура системи досягнень
Робоча схема — event-driven архітектура через центральний AchievementService. Замість того щоб кожен ігровий модуль знав про досягнення та викликав AchievementManager.CheckCondition(), модулі кидають події: GameEvent.EnemyKilled(enemyType, count), GameEvent.LevelCompleted(levelId, stars). AchievementService підписаний на потрібні події та сам оновлює лічильники. Подієва архітектура зменшує кількість багів у 3 рази порівняно з прямими викликами.
Кожне досягнення описується конфігом:
- тип (
incremental,single,compound) - список івентів, на які реагує
- умова завершення (лямбда або ScriptableObject з логікою)
- нагорода
Додавання нового досягнення — це новий конфіг, без змін в ігровому коді.
Синхронізація з платформами. Google Play Games Services та Apple Game Center мають власні лідерборди та досягнення, але працювати з ними напряму — біль. GPG SDK для Unity працює тільки на Android, Game Center — тільки на iOS. Для кроссплатформенних досягнень ми використовуємо проміжний шар: власна база зберігає майстер-стан, платформенні SDK оновлюються як сателіти. При конфлікті (офлайн-сесія) — мерж за принципом «беремо максимум» для інкрементальних лічильників. Синхронізація з Game Center та Google Play Games Services виконується через цей шар.
PlayFab та GameSparks надають готові серверні системи досягнень з API — для мобільних F2P це часто швидше та дешевше власного бекенду. Achievement (video games)
Для Unity досягнення реалізуємо через Jobs System, для Unreal Engine ачівки реалізуємо аналогічно.
Як уникнути читерів у лідерборді?
Клієнтська відправка score без валідації — пряма дорога до читерів на першому місці. Мінімум: score підписується HMAC-ключем на клієнті, сервер верифікує підпис. Нормальний варіант: сервер сам розраховує score за логами ігрової сесії, клієнт тільки відправляє події. Ми впроваджуємо античит лідерборду на обох рівнях: на клієнті — перевірка цілісності білда, на сервері — моніторинг аномалій (наприклад, різкий стрибок лічильника на 300% за 3 секунди).
Лідерборди: складність у масштабуванні
Для гри з 1000 одночасних гравців SQLite або PostgreSQL з ORDER BY score DESC LIMIT 100 працюють нормально. При 100k+ записів запит без правильних індексів починає гальмувати. При 1M+ — потрібен Redis сортований список.
Redis ZADD leaderboard {score} {userId} + ZREVRANK leaderboard {userId} дає O(log N) вставку та O(log N) отримання рангу. ZREVRANGE leaderboard 0 99 WITHSCORES — топ-100 за мікросекунди. Redis сортований список у 100 разів швидший за PostgreSQL для топ-100 лідерборду. Це стандарт для мобільних ігор з великою аудиторією.
Тижневі та сезонні лідерборди. Окрема таблиця (або окремий Redis сортований список) на період + cron-джоб для ротації. При ротації — снапшот переможців в архів, роздача нагород через чергу (не синхронно — при великій аудиторії синхронна роздача нагород уб'є сервер).
Що входить в роботу
| deliverable | опис |
|---|---|
| Документація API та схеми даних | опис подій, конфігів та endpoint'ів |
| Інструмент для геймдизайнера | редактор конфігів досягнень (web-інтерфейс або плагін в Unity/Unreal) |
| Інтеграція з платформами | GPG, Game Center, PlayFab — включаючи синхронізацію та мерж конфліктів |
| Навантажувальне тестування | перевірка лідерборду при 1000+ одночасних запитів |
| Підтримка після запуску | виправлення багів, доопрацювання конфігів, консультації команди |
Етапи розробки
- Проектування схеми — типи досягнень, події, зберігання стану, платформи.
- Серверна частина — таблиці/Redis, API endpoints, anti-cheat.
- Клієнтська інтеграція — AchievementService, підписки на події, UI.
- Платформенна синхронізація — GPG / Game Center / PlayFab.
- Інструменти для геймдизайнера — редактор конфігів досягнень.
- QA — тест ретроактивних досягнень, тест офлайн-сценаріїв, навантажувальний тест лідерборду.
| Масштаб | Термін |
|---|---|
| Локальні досягнення без сервера (мобайл/casual) | 1–2 тижні |
| Серверні досягнення + лідерборди для однієї платформи | 3–5 тижнів |
| Крос-платформена система з анти-читом і сезонними лідербордами | 6–12 тижнів |
Вартість визначається індивідуально після аналізу архітектури проекту та вимог до масштабованості. Оцініть ваш проект — напишіть нам, і ми запропонуємо план під ваш бюджет.






