Ваш игрок заходит третью неделю подряд, но ежедневные задания всё те же: «Собери 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 — свяжитесь с нами, получите консультацию. Закажите разработку — и ваши игроки будут возвращаться каждый день.







