카테고리 없음

20250507 TIL StatBlock 구조

note4973 2025. 5. 7. 21:23
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum StatType
{
    MaxHealth,
    MaxMana,
    Attack,
    Defence,
    CritChance,
    CritDamage,
    Evasion,
    Accuracy,
    VisionRange,
    AttackRange,
    FireDef,
    WaterDef,
    IceDef,
    ElectricDef,
    EarthDef,
    WindDef,
    LightDef,
    DarkDef,
    FireAtk,
    WaterAtk,
    IceAtk,
    ElectricAtk,
    EarthAtk,
    WindAtk,
    LightAtk,
    DarkAtk,

}
public enum ModifierType
{
    Flat,
    Precent,
}
[System.Serializable]
public class StatModifier
{
    public string source;
    public int value;
    public ModifierType type; // Flat, Percent
    public StatModifier() { }
    public StatModifier(string source, int value, ModifierType type)
    {
        this.source = source;
        this.value = value;
        this.type = type;
    }
}

[System.Serializable]
public class StatEntry
{
    public event Action onStatChanged;
    public int baseValue;
    private List<StatModifier> modifiers = new();

    public int Value
    {
        get
        {
            int flat = 0;
            float percent = 0f;
            foreach (StatModifier modifier in modifiers)
            {
                if(modifier.type == ModifierType.Flat)
                {
                    flat += modifier.value;
                }
                else if(modifier.type == ModifierType.Precent)
                {
                    percent += modifier.value;
                }
            }
            percent /= 100f;
            return Mathf.FloorToInt((baseValue + flat) * (1f + percent));
        }
    }

    public void AddModifier(string source, int value, ModifierType type)
    {
        modifiers.Add(new StatModifier ( source , value, type ));
        onStatChanged?.Invoke();
    }
    public void AddModifier(StatModifier statModifier)
    {
        modifiers.Add(statModifier);
        onStatChanged?.Invoke();
    }
    public void RemoveModifier(string source)
    {
        modifiers.RemoveAll(m => m.source == source);
        onStatChanged?.Invoke();
    }
    public void RemoveModifier(StatModifier statModifier)
    {
        modifiers.Remove(statModifier);
        onStatChanged?.Invoke();
    }
    public void SetBaseValue(int value)
    {
        baseValue = value;
        onStatChanged?.Invoke();
    }
}
[Serializable]
public class StatDictionary : SerializableDictionary<StatType, StatEntry> { }

[System.Serializable]
public class StatBlock
{
    [SerializeField]
    private StatDictionary stats = new();

    public StatBlock(Dictionary<StatType, int> baseStats)
    {
        foreach (var pair in baseStats)
            stats[pair.Key] = new StatEntry { baseValue = pair.Value };
    }

    public int Get(StatType type) => stats[type].Value;
    public StatEntry GetEntry(StatType type) => stats[type];

    public void AddModifier(StatType type, string source, int value, ModifierType modType)
    {
        stats[type].AddModifier(source, value, modType);
    }

    public void AddModifier(StatType type, StatModifier statModifier)
    {
        stats[type].AddModifier(statModifier);
    }

    public void RemoveModifier(StatType type, string source)
    {
        stats[type].RemoveModifier(source);
    }
    public void RemoveModifier(StatType type, StatModifier statModifier)
    {
        stats[type].RemoveModifier(statModifier);
    }
    public void SetBaseValue(StatType type, int baseValue)
    {
        stats[type].SetBaseValue(baseValue);
    }
}

 

 

statBlock 시스템을 이용해서 스탯시스템을 개편했다

 

기존의 스탯을 변경할 경우 baseStat값을 유지하기 어려웠고 버프나 장비, 레벨업 특전효과등을 관리하기 어려웠다 더불어 원래값으로 되돌리는 과정에서 값이 변조되는 경우도 있기에 statBlock 시스템을 이용하였다

 

statBlock은 key statType value statEntry로 구성된 딕셔너리로 관리되며 statEntry에서 baseValue와 statModifier로 구성된다

 

statModifier는 인스턴스 상태로 리스트로 관리되며 flat 과percent 타입으로 나뉘어 value 값에 계산된다

 

이를 이용하면 statmodifier 인스턴스를 통해 버프 장비 특전효과를 명확하게 관리하고 원본값을 유지하는것이 가능하다.