Как работает система уровней и прогрессии в играх

Если вы когда-нибудь играли в RPG или мобильные игры, то наверняка сталкивались с системой уровней. Персонаж набирает опыт, достигает нового уровня, получает награды — и хочется играть дальше. Но как это работает под капотом? Давайте разберёмся, как создать такую систему с нуля.

Разработка

6 мин

Базовая механика опыта и уровней

В основе любой системы прогрессии лежит простая идея: игрок выполняет действия, получает опыт, и когда опыта накапливается достаточно, происходит переход на новый уровень. Начнём с самого простого варианта на JavaScript:

class Player {
  constructor() {
    this.level = 1;
    this.experience = 0;
    this.experienceToNextLevel = 100;
  }

  gainExperience(amount) {
    this.experience += amount;
    
    while (this.experience >= this.experienceToNextLevel) {
      this.levelUp();
    }
  }

  levelUp() {
    this.experience -= this.experienceToNextLevel;
    this.level++;
    this.experienceToNextLevel = Math.floor(this.experienceToNextLevel * 1.5);
    
    console.log(`Поздравляем! Вы достигли ${this.level} уровня!`);
  }
}

const player = new Player();
player.gainExperience(150); // Получаем опыт и повышаем уровень

Обратите внимание на формулу расчёта опыта для следующего уровня. Мы умножаем текущее значение на 1.5, что создаёт экспоненциальную кривую роста. Это важный момент — если каждый уровень требует одинакового количества опыта, игра быстро станет скучной.

Различные кривые прогрессии

Существует несколько популярных подходов к расчёту требуемого опыта. Линейная прогрессия, когда каждый уровень требует на фиксированное количество больше опыта, подходит для коротких игр. Экспоненциальная кривая, как в примере выше, создаёт ощущение постепенного усложнения. Логарифмическая кривая делает первые уровни быстрыми, а последующие замедляются.

Вот пример с разными формулами:

class ProgressionSystem {
  // Линейная прогрессия: 100, 200, 300, 400...
  static linear(level, baseXP = 100) {
    return baseXP * level;
  }

  // Экспоненциальная: 100, 150, 225, 337.5...
  static exponential(level, baseXP = 100, multiplier = 1.5) {
    return Math.floor(baseXP * Math.pow(multiplier, level - 1));
  }

  // Полиномиальная: 100, 400, 900, 1600...
  static polynomial(level, baseXP = 100) {
    return baseXP * Math.pow(level, 2);
  }

  // Гибридная формула (как в Pokemon)
  static hybrid(level) {
    return Math.floor(1.2 * Math.pow(level, 3));
  }
}

// Посмотрим, как растёт требование опыта
for (let level = 1; level <= 5; level++) {
  console.log(`Уровень ${level}:`);
  console.log(`  Линейная: ${ProgressionSystem.linear(level)}`);
  console.log(`  Экспоненциальная: ${ProgressionSystem.exponential(level)}`);
  console.log(`  Полиномиальная: ${ProgressionSystem.polynomial(level)}`);
}

Какую формулу выбрать?

Это зависит от вашей игры. Для мобильных казуальных игр часто используют быструю прогрессию в начале, чтобы захватить игрока, затем замедляют темп. В хардкорных RPG прогрессия может быть медленной и требовательной с самого начала.

Добавляем награды за уровень

Повышение уровня без наград — это упущенная возможность. Игроки должны чувствовать, что их прогресс что-то значит. Давайте добавим систему наград:

class Player {
  constructor() {
    this.level = 1;
    this.experience = 0;
    this.health = 100;
    this.attack = 10;
    this.defense = 5;
    this.skillPoints = 0;
  }

  levelUp() {
    this.level++;
    
    // Увеличиваем базовые характеристики
    this.health += 20;
    this.attack += 3;
    this.defense += 2;
    this.skillPoints += 5;
    
    // Каждый 5-й уровень даём особую награду
    if (this.level % 5 === 0) {
      this.unlockNewAbility();
    }
    
    // Восстанавливаем здоровье при повышении уровня
    this.currentHealth = this.health;
    
    console.log(`
      🎉 Уровень ${this.level}!
      Здоровье: ${this.health}
      Атака: ${this.attack}
      Защита: ${this.defense}
      Очки навыков: ${this.skillPoints}
    `);
  }

  unlockNewAbility() {
    const abilities = [
      'Огненный шар',
      'Ледяная стрела',
      'Щит силы',
      'Удар молнии'
    ];
    const abilityIndex = Math.floor(this.level / 5) - 1;
    if (abilityIndex < abilities.length) {
      console.log(`✨ Разблокирована способность: ${abilities[abilityIndex]}`);
    }
  }
}

Визуализация прогресса

Недостаточно просто хранить числа — игрокам нужно видеть свой прогресс. Давайте создадим простой прогресс-бар:

class ProgressBar {
  static draw(current, required, width = 20) {
    const percentage = current / required;
    const filledWidth = Math.floor(percentage * width);
    const emptyWidth = width - filledWidth;
    
    const filled = '█'.repeat(filledWidth);
    const empty = '░'.repeat(emptyWidth);
    const percentText = Math.floor(percentage * 100);
    
    return `[${filled}${empty}] ${percentText}% (${current}/${required})`;
  }
}

const player = new Player();
console.log('Опыт:', ProgressBar.draw(player.experience, player.experienceToNextLevel));

player.gainExperience(75);
console.log('Опыт:', ProgressBar.draw(player.experience, player.experienceToNextLevel));

Для веб-игр можно использовать HTML и CSS для создания более красивых прогресс-баров. Вот быстрый пример:

class UIManager {
  static updateExpBar(player) {
    const percentage = (player.experience / player.experienceToNextLevel) * 100;
    
    const expBar = document.getElementById('exp-bar');
    const expText = document.getElementById('exp-text');
    
    expBar.style.width = `${percentage}%`;
    expText.textContent = `${player.experience} / ${player.experienceToNextLevel} XP`;
  }

  static showLevelUp(player) {
    const notification = document.createElement('div');
    notification.className = 'level-up-notification';
    notification.textContent = `Уровень ${player.level}!`;
    document.body.appendChild(notification);
    
    // Анимация появления и исчезновения
    setTimeout(() => notification.classList.add('show'), 10);
    setTimeout(() => {
      notification.classList.remove('show');
      setTimeout(() => notification.remove(), 300);
    }, 2000);
  }
}

Система престижа и переродений

Многие современные игры используют систему престижа — когда игрок достигает максимального уровня, он может начать заново, но с бонусами. Это добавляет реиграбельность:

class PrestigeSystem {
  constructor() {
    this.prestigeLevel = 0;
    this.prestigePoints = 0;
  }

  canPrestige(player) {
    return player.level >= 100;
  }

  prestige(player) {
    if (!this.canPrestige(player)) {
      console.log('Недостаточно уровня для престижа!');
      return false;
    }

    this.prestigeLevel++;
    this.prestigePoints += Math.floor(player.level / 10);
    
    // Сбрасываем игрока, но сохраняем бонусы
    const expBonus = 1 + (this.prestigeLevel * 0.1); // +10% опыта за каждый престиж
    const statBonus = this.prestigeLevel * 5; // +5 к стартовым характеристикам
    
    player.reset(expBonus, statBonus);
    
    console.log(`
      🌟 Престиж ${this.prestigeLevel}!
      Бонус к опыту: +${(expBonus - 1) * 100}%
      Бонус к характеристикам: +${statBonus}
      Очки престижа: ${this.prestigePoints}
    `);
    
    return true;
  }

  // Постоянные улучшения за очки престижа
  buyPermanentUpgrade(upgrade) {
    const upgrades = {
      'double_xp': { cost: 10, effect: 'Удвоенный опыт' },
      'start_level_10': { cost: 15, effect: 'Старт с 10 уровня' },
      'bonus_gold': { cost: 20, effect: '+50% золота' }
    };

    const selected = upgrades[upgrade];
    if (!selected) return false;
    
    if (this.prestigePoints >= selected.cost) {
      this.prestigePoints -= selected.cost;
      console.log(`Куплено: ${selected.effect}`);
      return true;
    }
    
    return false;
  }
}

Балансировка прогрессии

Самая сложная часть — это правильно сбалансировать систему. Игрок должен чувствовать прогресс, но не слишком быстро. Несколько советов: первые пять уровней должны проходиться быстро, чтобы захватить игрока и показать механики. Средние уровни — это основной контент, здесь темп должен быть комфортным. Поздние уровни могут требовать серьёзных усилий, это создаёт ощущение достижения.

Важно тестировать на реальных игроках. То, что кажется сбалансированным разработчику, может быть слишком быстрым или медленным для обычного игрока. Используйте аналитику, чтобы отслеживать, на каких уровнях игроки застревают или бросают игру.

Вот простая система логирования для анализа:

class Analytics {
  static logLevelUp(player, timeSpent) {
    const data = {
      level: player.level,
      timeSpent: timeSpent,
      timestamp: new Date().toISOString()
    };
    
    // В реальной игре отправляем на сервер
    console.log('Analytics:', data);
    
    // Сохраняем локально для анализа
    const history = JSON.parse(localStorage.getItem('levelHistory') || '[]');
    history.push(data);
    localStorage.setItem('levelHistory', JSON.stringify(history));
  }

  static getAverageLevelTime() {
    const history = JSON.parse(localStorage.getItem('levelHistory') || '[]');
    if (history.length === 0) return 0;
    
    const total = history.reduce((sum, entry) => sum + entry.timeSpent, 0);
    return total / history.length;
  }
}

Продвинутые техники

Современные игры часто используют несколько параллельных систем прогрессии. Например, уровень персонажа, уровень навыков, боевой рейтинг, сезонный прогресс. Каждая система даёт игроку что-то новое и держит вовлечённость на разных этапах игры. Также популярны дневные и недельные цели, которые дают дополнительный опыт и награды, стимулируя игроков возвращаться в игру регулярно.

Не забывайте про обратную связь. Каждое действие игрока должно показывать прогресс: числа опыта, анимации, звуковые эффекты, визуальные эффекты при повышении уровня. Всё это создаёт ощущение удовлетворения и мотивирует продолжать играть.

Заключение: Система уровней и прогрессии — это целая наука, которая объединяет программирование, геймдизайн и психологию игрока. Правильно реализованная система держит игроков вовлечёнными часами, создавая тот самый эффект "ещё один уровень". Экспериментируйте с формулами, тестируйте на реальных игроках и не бойтесь менять баланс после релиза.

🎓 Продолжайте обучение!

Изучить эту тему глубже, а также освоить разработку игр, веб-приложений и многое другое можно в Кодике — нашей образовательной платформе с курсами для начинающих разработчиков.

А ещё у нас есть крутой телеграм-канал с дружеским комьюнити, где разработчики обсуждают код, делятся опытом и помогают друг другу расти.

Комментарии