Разработка системы достижений мобильной игры
Система достижений — не просто список «убей 100 врагов». Правильно спроектированная, она управляет retention: игрок возвращается, потому что хочет закрыть ачивку, которая требует 7 дней подряд входить в игру или убить конкретного босса. Достижения также дают долгосрочные цели пользователям, которые прошли основной контент.
Архитектура: локальная vs серверная
Для большинства мобильных игр архитектура выглядит так:
- Прогресс достижений — клиент + серверная синхронизация (Google Play Games / Game Center / PlayFab)
- Выдача наград — только сервер (или Platform SDK с верификацией)
- Отображение — клиент
Хранить прогресс только локально рискованно: переустановка = потеря ачивок = негативный опыт. PlayFab Player Data или Google Play Games Snapshots решают это.
Модель данных
[Serializable]
public class Achievement
{
public string id;
public string titleKey; // локализация
public string descriptionKey;
public AchievementType type; // Counter, OneTime, Streak
public int targetValue;
public List<Reward> rewards;
public bool isSecret; // скрытые до выполнения
public string[] requiredAchievements; // цепочки зависимостей
}
public enum AchievementType
{
OneTime, // выполнено или нет
Counter, // прогресс 0..targetValue
Streak, // N дней подряд
Cumulative // накопительно за всё время
}
[Serializable]
public class AchievementProgress
{
public string achievementId;
public int currentValue;
public bool isUnlocked;
public DateTime? unlockedAt;
public bool rewardClaimed;
}
AchievementsManager
public class AchievementsManager : MonoBehaviour
{
public static AchievementsManager Instance { get; private set; }
private Dictionary<string, AchievementProgress> _progress;
private AchievementDatabase _database;
// Вызывается из игровой логики
public void TrackEvent(string eventType, int value = 1, Dictionary<string, object> context = null)
{
foreach (var achievement in _database.GetAchievementsByEvent(eventType))
{
var progress = GetOrCreate(achievement.id);
if (progress.isUnlocked) continue;
switch (achievement.type)
{
case AchievementType.Counter:
case AchievementType.Cumulative:
progress.currentValue += value;
break;
case AchievementType.OneTime:
progress.currentValue = 1;
break;
}
if (progress.currentValue >= achievement.targetValue)
Unlock(achievement, progress);
}
SaveProgress();
}
private void Unlock(Achievement achievement, AchievementProgress progress)
{
progress.isUnlocked = true;
progress.unlockedAt = DateTime.UtcNow;
// Уведомление игрока
AchievementPopupUI.Instance.Show(achievement);
// Аналитика
GameAnalytics.NewDesignEvent($"Achievement:Unlocked:{achievement.id}");
// Синхронизация с платформой
SyncWithPlatform(achievement);
}
}
Метод TrackEvent — единственная точка входа из геймплея. Это значит, что добавление нового достижения не требует изменений в боевой логике, системе квестов или магазине — только новая запись в AchievementDatabase.
Streak-достижения
Серия входов подряд — один из лучших retention-инструментов. Требует аккуратной обработки дат:
public void RecordDailyLogin()
{
var lastLogin = PlayerPrefs.GetString("last_login_date", "");
var today = DateTime.UtcNow.Date.ToString("yyyy-MM-dd");
var yesterday = DateTime.UtcNow.Date.AddDays(-1).ToString("yyyy-MM-dd");
if (lastLogin == today) return; // уже засчитано сегодня
int streak = PlayerPrefs.GetInt("login_streak", 0);
streak = (lastLogin == yesterday) ? streak + 1 : 1; // сброс если пропустил день
PlayerPrefs.SetString("last_login_date", today);
PlayerPrefs.SetInt("login_streak", streak);
TrackEvent("daily_login_streak", streak);
}
Важно использовать UTC, а не локальное время — иначе игрок в UTC+12 может получить двойной бонус при смене дня.
Интеграция с платформенными достижениями
Google Play Games и Game Center имеют собственные ачивки, которые видны в платформенном интерфейсе:
// Google Play Games (Play Games Services v2)
PlayGamesPlatform.Instance.UnlockAchievement("CgkI6ISmlocOEAIQAQ");
// Game Center (iOS)
GKAchievement achievement = new GKAchievement("first_boss_killed");
achievement.percentComplete = 100;
GKAchievement.Report(new[] { achievement }, (error) => { });
Синхронизируем только те достижения, которые имеют смысл на платформе. Не нужно дублировать все 100 внутриигровых ачивок в Game Center — только ключевые milestone.
Что входит в работу
- Проектирование схемы достижений и системы событий
- Реализация
AchievementsManagerс типами Counter/OneTime/Streak - Синхронизация прогресса с PlayFab / Google Play Games / Game Center
- UI: список достижений, прогресс-бары, popup при разблокировке
- Система наград: валюта, предметы, косметика
- Аналитика разблокировок для балансировки сложности
- Локализация заголовков и описаний
Сроки
Базовая система без платформенной интеграции: 4–6 дней. Полная система с синхронизацией, UI и наградами: 1,5–2,5 недели. Стоимость рассчитывается индивидуально.







