Реалізація Gacha/Lootbox механіки мобільної гри з pity-системою
Уявіть: у вас майже готова RPG, залишилося впровадити гачу, але юзер-тест показав, що гравці кидають після 50 ролів без легендарки — комбінація без pity-системи вбиває утримання. Або гірше: ви випустили оновлення, а через день у App Store приходить відмова — ймовірності не показані. Такі проблеми коштують грошей: переробка та повторна модерація можуть затягнутися на тижні, а тим часом конкуренти забирають вашу аудиторію. Ми допомагаємо цього уникнути: за 3–4 дні ставимо базову gacha із захистом від невдач, за 7–10 — повноцінну систему з банерами, анімаціями та звітами для маркету. Наш досвід — понад 40 проєктів, і кожен проходив рев'ю з першого разу. Не ризикуйте релізом — зв'яжіться з нами для аудиту вашої поточної механіки.
Математична модель ймовірностей
Базова gacha — зважений випадковий вибір з пулу нагород. Проста реалізація:
data class GachaItem(val id: String, val rarity: Rarity, val weight: Int) fun rollGacha(pool: List<GachaItem>): GachaItem { val totalWeight = pool.sumOf { it.weight } var random = Random.nextInt(totalWeight) for (item in pool) { random -= item.weight if (random < 0) return item } return pool.last() } Приклад розподілу ваг:
- Common: weight 1000 → ~58.8% шанс
- Rare: weight 500 → ~29.4%
- Epic: weight 150 → ~8.8%
- Legendary: weight 50 → ~2.9%
Сумарна вага: 1700. Шанс legendary: 50/1700 ≈ 2.94%.
Як працює pity-система?
Pity (гарантована нагорода) — механіка, яка гарантує legendary після N невдалих спроб. Без pity у гравця може бути streak з 200 ролів без legendary — математично можливо, практично руйнує досвід.
Soft pity — починаючи з N-го ролу ймовірність legendary зростає. Genshin Impact використовує цей підхід: з 74-го ролу шанс 5* починає зростати на 6% кожен рол.
Hard pity — рівно на N-му ролі legendary гарантований. Простіше реалізувати та чесніше комунікувати гравцю.
data class PlayerGachaPity( val rollsSinceLastLegendary: Int, val softPityStart: Int = 74, val hardPityAt: Int = 90 ) fun calculateEffectiveProbability(baseProbability: Float, pity: PlayerGachaPity): Float { if (pity.rollsSinceLastLegendary >= pity.hardPityAt) return 1.0f if (pity.rollsSinceLastLegendary >= pity.softPityStart) { val excess = pity.rollsSinceLastLegendary - pity.softPityStart return minOf(1.0f, baseProbability + excess * 0.06f) } return baseProbability } Pity-лічильник зберігається на сервері, не на клієнті. Клієнтський лічильник обнуляється при перевстановленні — гравець втрачає накопичений pity, що викликає справедливе обурення та чарджбеки.
Навіщо серверна генерація?
Результат гача-ролу не можна генерувати на клієнті. Серверна генерація в 100 разів надійніша за клієнтську — зламати її майже неможливо. Схема:
- Клієнт надсилає запит
POST /gacha/rollзuserId,gachaPoolId, кількістю ролів, токеном оплати - Сервер перевіряє баланс/транзакцію, дістає pity-лічильник, генерує результат з seeded PRNG
- Сервер записує результат, оновлює pity, повертає
rollId+ результати - Клієнт відображає анімацію та показує результати
Seed для PRNG генерується на сервері, клієнт не може передбачити або вплинути на результат.
Анімація відкриття
Анімація gacha-ролу — не просто прикраса, це психологічно значущий момент. Тривалість 2–4 секунди, наростаючий саспенс перед reveal. Для мобільної реалізації використовуємо:
- Unity Animator або Spine для 2D-анімацій карт/яєць
- Particle System для ефектів при reveal рідкісних нагород
- Haptic feedback (UIImpactFeedbackGenerator на iOS, VibrationEffect на Android) в момент reveal
Multi-pull анімації (x10 рол) потребують окремої логіки: показуємо всі результати послідовно зі зростаючим темпом, common швидко, legendary — з повноекранним ефектом.
Регуляторні вимоги
App Store вимагає відображення ймовірностей «перед покупкою». Google Play — аналогічна вимога. Реалізація: екран «Деталі гача-пулу» з таблицею ймовірностей за типами нагород. Цей екран відкривається кнопкою «i» (інформація) поруч з кнопкою ролу.
| Рідкість | Ймовірність | Гарантія (hard pity) |
|---|---|---|
| Common | 58.8% | — |
| Rare | 29.4% | — |
| Epic | 8.8% | 40 ролів |
| Legendary | 2.9% | 90 ролів |
Які типи gacha-банерів існують?
| Тип банеру | Тривалість | Rate-up | Pity сумісність | Дохідність |
|---|---|---|---|---|
| Standard | Постійно | Ні | Так | Стабільна |
| Rate-up | 7–14 днів | Так | Так (з гарантом) | Висока |
| Featured | 7–14 днів | Так | 50/50 guarantee | Максимальна |
Rate-up banner — тимчасовий пул з підвищеним шансом конкретного персонажа/предмета. Створює urgency та піки доходу. Standard banner — постійний пул, приймає «втрачені» pity-перемоги в системах з гарантом. Featured banner з guarantee — якщо rate-up не випав на 1-му legendary, наступний guaranteed буде featured (система «50/50»).
Чек-лист: що входить в роботу
- Аналіз вимог та проектування математичної моделі
- Реалізація серверної та клієнтської логіки (Swift/Kotlin/Flutter)
- Інтеграція pity-системи та rate-up банерів
- Верстка UI з відображенням ймовірностей
- Створення анімацій відкриття (2D/3D)
- Тестування на навантаження (500+ одночасних ролів)
- Підготовка документів для публікації в App Store та Google Play
- Пост-релізна підтримка: моніторинг, доопрацювання за метриками
Терміни орієнтовно
Базова gacha з pity та серверною генерацією — 3–4 дні. Повна система з кількома типами банерів, UI ймовірностей, анімаціями та аналітикою — 7–10 днів. Вартість розраховується індивідуально — напишіть нам для оцінки.
Отримайте консультацію — ми допоможемо спроектувати gacha-систему, яка принесе прибуток та пройде модерацію.







