Ваш игрок заходит третью неделю подряд, но ежедневные задания всё те же: «Собери 3 монеты». Ему скучно, он уходит. Retention падает. Мы, как разработчики с опытом в мобильной геймификации, знаем, как превратить daily quests в мощный инструмент удержания. Правильно реализованная динамическая система увеличивает Day-7 retention в полтора-два раза для casual-игр с DAU до 100 000. Экономия на разработке с нуля достигает 40% за счёт готовых шаблонов и продуманной архитектуры.
Как генерировать задания: статические vs динамические?
Статические задания — фиксированный пул, из которого случайно выбираются 3-5 на день. Просто в реализации, предсказуемо для игрока, но быстро приедается. Динамические задания — генерируются на основе прогресса игрока и активности. Новичку дают «пройди 3 уровня», ветерану — «собери 500 ресурсов типа X». Сложнее в реализации, но даёт лучший retention.
| Характеристика | Статические | Динамические |
|---|---|---|
| Сложность реализации | Низкая | Средняя/Высокая |
| Retention | Ниже | Выше |
| Предсказуемость | Полная | Частичная |
| Удовлетворение игрока | Падает со временем | Растет с прогрессом |
Почему streak так важен для retention?
Streak (серия дней подряд) создаёт долгосрочную цель поверх ежедневных задач. Игрок возвращается, чтобы не потерять прогресс. Мы реализуем подсчёт дней и выдачу бонусов с нарастающей ценностью: на 7-й день — редкий предмет, на 30-й — легендарный. Это увеличивает Day-30 retention в 3 раза по нашим данным.
// При завершении всех заданий дня void OnAllQuestsCompleted() { var streak = PlayerPrefs.GetInt("daily_quest_streak", 0); var lastCompletedDate = PlayerPrefs.GetString("quest_last_completed", ""); var yesterday = DateTime.UtcNow.Date.AddDays(-1).ToString("yyyy-MM-dd"); var today = DateTime.UtcNow.Date.ToString("yyyy-MM-dd"); streak = (lastCompletedDate == yesterday) ? streak + 1 : 1; PlayerPrefs.SetInt("daily_quest_streak", streak); PlayerPrefs.SetString("quest_last_completed", today); var reward = CalculateStreakReward(streak); InventoryManager.Instance.AddReward(reward); GameAnalytics.NewDesignEvent("DailyQuests:StreakCompleted", streak); } Схема данных: шаблоны и активные задания
Для динамической системы удобно хранить шаблоны и активные задания в отдельных классах:
[Serializable] public class QuestTemplate { public string templateId; public string type; // "complete_levels", "collect_items", "defeat_enemies" public int[] targetValues; // варианты сложности: [3, 5, 10] public string[] targetParams; // для collect: ["wood", "stone", "gold"] public QuestRewardTier[] rewardTiers; // награда по сложности public int minPlayerLevel; public int maxPlayerLevel; // -1 = без ограничения } [Serializable] public class ActiveQuest { public string questId; public string templateId; public string type; public string targetParam; public int targetValue; public int currentValue; public bool isCompleted; public bool rewardClaimed; public DateTime expiresAt; } DailyQuestManager: генерация и трекинг
Реализуем менеджер, который каждый день генерирует новый набор заданий и отслеживает прогресс:
public class DailyQuestManager : MonoBehaviour { private const int QUEST_SLOTS = 3; private List<ActiveQuest> _activeQuests = new(); private QuestDatabase _database; public void GenerateDailyQuests() { _activeQuests.Clear(); var playerLevel = PlayerData.Level; var random = new System.Random(GetDailySeed()); // seed = дата, одинаковы для всех var eligibleTemplates = _database.Templates .Where(t => playerLevel >= t.minPlayerLevel && (t.maxPlayerLevel == -1 || playerLevel <= t.maxPlayerLevel)) .ToList(); var selectedTemplates = eligibleTemplates .OrderBy(_ => random.Next()) .Take(QUEST_SLOTS) .ToList(); foreach (var template in selectedTemplates) { var difficulty = SelectDifficulty(template, playerLevel); _activeQuests.Add(CreateQuestFromTemplate(template, difficulty)); } SaveQuests(); } private int GetDailySeed() { return DateTime.UtcNow.Date.GetHashCode() ^ PlayerData.UserId.GetHashCode(); } public void TrackProgress(string questType, string param, int amount) { foreach (var quest in _activeQuests.Where(q => !q.isCompleted && q.type == questType)) { if (!string.IsNullOrEmpty(quest.targetParam) && quest.targetParam != param) continue; quest.currentValue += amount; if (quest.currentValue >= quest.targetValue) { quest.isCompleted = true; OnQuestCompleted(quest); } } SaveQuests(); } } Для выбора сложности используется алгоритм, подбирающий targetValue из массива в шаблоне в зависимости от уровня игрока. Например, для новичка (уровень 1-5) берется минимальное значение, для среднего (6-15) — среднее, для высокого (16+) — максимальное.
Что даёт серверная генерация заданий?
Серверная генерация обязательна, если задания связаны с реальными наградами (IAP-эквивалент). Клиент запрашивает задания, сервер (например, PlayFab Cloud Script) возвращает сгенерированный список и верифицирует прогресс перед выдачей награды. Это защищает экономику от взлома. Для простых игр без ценных наград клиентская генерация проще и быстрее.
Как адаптировать сложность под игрока?
Одна из частых ошибок — давать ветерану те же задания, что и новичку. Мы используем систему профилей сложности: на основе уровня, времени в игре и последних действий выбирается подходящий шаблон. Например:
- Новичок (1-5 level):
complete_levelsс target=3, награда — монеты. - Средний (6-15):
collect_itemsс target=100, награда — редкий ресурс. - Ветеран (16+):
defeat_enemyс параметром elite, target=10, награда — уникальный предмет.
Это поддерживает интерес и не даёт заданиям стать рутиной.
Интеграция в геймплей: бесшовный трекинг
Трекинг заданий должен быть автоматическим — игрок не думает «надо нажать кнопку учёта», он просто играет:
// В системе боёвки: void OnEnemyDefeated(Enemy enemy) { DailyQuestManager.Instance.TrackProgress("defeat_enemies", enemy.type, 1); AchievementsManager.Instance.TrackEvent("enemy_defeated", 1); // ... } // В системе сбора ресурсов: void OnResourceCollected(string resourceId, int amount) { DailyQuestManager.Instance.TrackProgress("collect_items", resourceId, amount); // ... } Один вызов из геймплейной системы — все задания с нужным типом обновляются автоматически.
Что входит в работу
- Проектирование системы заданий (типы, сложность, награды)
- Реализация DailyQuestManager с трекингом и streak
- Интеграция с геймплеем и UI
- Серверная генерация (по необходимости)
- Документация по использованию и кастомизации
- Передача исходного кода и доступ к репозиторию
- Поддержка на этапе запуска
Пошаговая реализация под ключ
| Этап | Что делаем | Срок |
|---|---|---|
| Анализ | Определяем типы заданий, сложность, награды. Опираемся на документацию Unity | 1-2 дня |
| Проектирование | Создаем шаблоны и систему сложности | 1 день |
| Разработка | Пишем DailyQuestManager, трекинг, UI | 2-4 дня |
| Интеграция | Подключаем к геймплею, настраиваем streak | 1-2 дня |
| Тестирование | Проверяем сброс, награды, баланс | 1-2 дня |
| Запуск | Публикуем в магазины | 1 день |
Ориентировочный срок выполнения клиентской системы с базовым набором заданий — 4–7 дней. Полная система с серверной генерацией, streak и сложным UI — 2–3 недели. Стоимость рассчитывается индивидуально после оценки проекта. Если хотите обсудить вашу систему daily quests — свяжитесь с нами, получите консультацию. Закажите разработку — и ваши игроки будут возвращаться каждый день.







