← Назад к вопросам

Реализовать систему прокачки персонажа

2.0 Middle🔥 241 комментариев
#C# и ООП#UI#Коллекции и структуры данных#Паттерны проектирования

Условие

Реализуйте систему уровней и прокачки персонажа.

Требования

  1. Получение опыта за действия
  2. Кривая опыта для уровней
  3. Очки навыков при повышении уровня
  4. Дерево навыков
  5. Сохранение прогресса
  6. UI отображение

Статы

  • Сила, ловкость, интеллект
  • Здоровье, мана
  • Урон, защита

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Система прокачки и уровней персонажа

Реализую полнофункциональную систему развития персонажа с опытом, уровнями, деревом навыков, прокачкой статов и сохранением прогресса. Используется ScriptableObject конфиги и JSON сериализация.

Модель персонажа и опыта

[System.Serializable]
public class CharacterStats
{
    public int strength = 10;     // Сила - увеличивает урон и здоровье
    public int agility = 10;      // Ловкость - увеличивает защиту и скорость
    public int intelligence = 10; // Интеллект - увеличивает ману и урон магии

    public int maxHealth;
    public int currentHealth;
    public int maxMana;
    public int currentMana;
    public float armor;           // Защита
    public float physicalDamage;  // Урон

    public void RecalculateStats()
    {
        maxHealth = 100 + strength * 5;
        maxMana = 50 + intelligence * 3;
        armor = agility * 0.5f;
        physicalDamage = 10f + strength * 1.5f;
    }
}

public class ExperienceConfig : ScriptableObject
{
    [SerializeField] private List<int> experiencePerLevel; // Кривая опыта
    [SerializeField] private int skillPointsPerLevel = 5;

    public int GetExperienceForLevel(int level)
    {
        if (level < 0 || level >= experiencePerLevel.Count)
            return 0;
        return experiencePerLevel[level];
    }

    public int SkillPointsPerLevel => skillPointsPerLevel;
}

Система уровней с отслеживанием опыта

public class LevelingSystem : MonoBehaviour
{
    [SerializeField] private ExperienceConfig expConfig;
    [SerializeField] private CharacterStats stats;
    
    private int currentLevel = 1;
    private int currentExperience = 0;
    private int skillPoints = 0;

    public int CurrentLevel => currentLevel;
    public int CurrentExperience => currentExperience;
    public int ExperienceForNextLevel => expConfig.GetExperienceForLevel(currentLevel);
    public float LevelProgress => (float)currentExperience / ExperienceForNextLevel;
    public int SkillPoints => skillPoints;

    public void GainExperience(int amount)
    {
        currentExperience += amount;
        OnExperienceGained?.Invoke(amount, currentExperience);

        while (currentExperience >= ExperienceForNextLevel)
        {
            LevelUp();
        }
    }

    private void LevelUp()
    {
        currentExperience -= ExperienceForNextLevel;
        currentLevel++;
        skillPoints += expConfig.SkillPointsPerLevel;
        stats.RecalculateStats();
        
        OnLevelUp?.Invoke(currentLevel, expConfig.SkillPointsPerLevel);
    }

    public bool TrySpendSkillPoint(string statName)
    {
        if (skillPoints <= 0)
            return false;

        skillPoints--;
        IncreaseStat(statName);
        OnSkillPointSpent?.Invoke(skillPoints);
        return true;
    }

    private void IncreaseStat(string statName)
    {
        switch (statName.ToLower())
        {
            case "strength":
                stats.strength++;
                break;
            case "agility":
                stats.agility++;
                break;
            case "intelligence":
                stats.intelligence++;
                break;
        }
        stats.RecalculateStats();
    }

    public event System.Action<int, int> OnExperienceGained;
    public event System.Action<int, int> OnLevelUp;
    public event System.Action<int> OnSkillPointSpent;
}

Дерево навыков (Skill Tree)

[System.Serializable]
public class SkillNode
{
    public string skillId;
    public string skillName;
    public string description;
    public int requiredLevel;
    public int skillPointCost = 1;
    public List<string> prerequisiteSkills;
    public Sprite icon;
    public bool isUnlocked;

    [NonSerialized]
    public List<SkillNode> children = new();
}

public class SkillTreeSystem : MonoBehaviour
{
    [SerializeField] private List<SkillNode> rootSkills;
    [SerializeField] private Dictionary<string, SkillNode> skillNodeMap;
    [SerializeField] private LevelingSystem levelingSystem;
    private Dictionary<string, bool> unlockedSkills = new();

    public bool TryUnlockSkill(string skillId)
    {
        if (!skillNodeMap.TryGetValue(skillId, out var skill))
            return false;

        if (levelingSystem.CurrentLevel < skill.requiredLevel)
            return false;

        if (levelingSystem.SkillPoints < skill.skillPointCost)
            return false;

        foreach (var prereq in skill.prerequisiteSkills)
        {
            if (!unlockedSkills.ContainsKey(prereq) || !unlockedSkills[prereq])
                return false;
        }

        unlockedSkills[skillId] = true;
        skill.isUnlocked = true;
        OnSkillUnlocked?.Invoke(skill);
        return true;
    }

    public event System.Action<SkillNode> OnSkillUnlocked;
}

Система сохранения (JSON)

[System.Serializable]
public class CharacterSaveData
{
    public int currentLevel;
    public int currentExperience;
    public int skillPoints;
    public CharacterStats stats;
    public Dictionary<string, bool> unlockedSkills;
    public string lastSaveTime;
}

public class SaveSystem : MonoBehaviour
{
    [SerializeField] private string saveFilePath = "Saves/character.json";

    public void SaveCharacter(CharacterStats stats, int level, int exp, int skillPoints)
    {
        var saveData = new CharacterSaveData
        {
            currentLevel = level,
            currentExperience = exp,
            skillPoints = skillPoints,
            stats = stats,
            lastSaveTime = System.DateTime.Now.ToString()
        };

        string json = JsonUtility.ToJson(saveData, true);
        System.IO.File.WriteAllText(saveFilePath, json);
    }

    public CharacterSaveData LoadCharacter()
    {
        if (!System.IO.File.Exists(saveFilePath))
            return null;

        string json = System.IO.File.ReadAllText(saveFilePath);
        return JsonUtility.FromJson<CharacterSaveData>(json);
    }
}

Преимущества решения

  • Экспоненциальная кривая опыта для реалистичного прогресса
  • Дерево навыков с предусловиями и зависимостями
  • Динамический расчёт статов при прокачке
  • JSON сериализация для сохранения прогресса
  • Event система для слабой связанности компонентов
  • Модульная архитектура для расширяемости