//재화 종류

public enum CurrencyType

{

    ilmenite,

    trinitite,

    iron58

}


public class CurrencyManager : MonoBehaviour

{

    public static CurrencyManager instance;

    void Awake()

    {

        if (instance == null)

        {

            instance = this;

            DontDestroyOnLoad(gameObject);


            InitializeCurrencies();

            InitializeMultipliers();


            LoadSavedData();


            shower = new CheckCurrency[System.Enum.GetValues(typeof(CurrencyType)).Length];

            for (int i = 0; i < shower.Length; i++)

            {

                shower[i] = new CheckCurrency();

            }

        }

        else

            Destroy(gameObject);

    }


    //재화 전체 관리 딕셔너리

    [SerializeField]

    private Dictionary<CurrencyType, BigDouble> currencies = new Dictionary<CurrencyType, BigDouble>();


    //재화 배율 관리 배열

    [SerializeField]

    private double[] additivePercentages;

    [SerializeField]

    private double[] multiplicativeMultipliers;


    //재화 변경 이벤트

    public event Action<CurrencyType,BigDouble> OnCurrencyChanged;


    #region Currency


    // 배율 배열 초기화 (CurrencyType 개수만큼)

    private void InitializeCurrencies()

    {

        additivePercentages = new double[System.Enum.GetValues(typeof(CurrencyType)).Length];


        foreach (CurrencyType type in System.Enum.GetValues(typeof(CurrencyType)))

        {

            currencies[type] = 0;

            additivePercentages[(int)type] = 1f;  // 기본 배율 1

        }

    }


    //재화 조회 

    public BigDouble GetCurrency(CurrencyType type)

    {

        if (!currencies.ContainsKey(type))

            currencies[type] = 0;

        return currencies[type];

    }


    //재화 추가

    public void AddCurrency(CurrencyType type, BigDouble amount)

    {

        if (!currencies.ContainsKey(type))

            currencies[type] = 0;


        BigDouble scaledAmount = amount;

        Debug.Log($"Initial amount: {scaledAmount}");


        // 배율 계산

        BigDouble additivePercentage = additivePercentages[(int)type]; // % 값 (예: 10%)

        BigDouble multiplicativeMultiplier = multiplicativeMultipliers[(int)type]; // 배수 값 (예: 1.5)


        // 총 배율 계산

        BigDouble totalMultiplier = (1 + (additivePercentage / 100.0)) * multiplicativeMultiplier;

        Debug.Log($"Total multiplier: {totalMultiplier}");


        // 스케일링된 금액 계산

        scaledAmount *= totalMultiplier;

        Debug.Log($"Final scaled amount: {scaledAmount}");


        Debug.Log($"Original: {NumberFormatter.FormatNumber(amount)}, " +

                  $"After multipliers: {NumberFormatter.FormatNumber(scaledAmount)}");


        // 상대적인 증가 적용

        BigDouble currentAmount = currencies[type];


        if (currentAmount > 1e15 && scaledAmount < currentAmount * 1e-5)

        {

            // 증가량이 너무 작아서 반영되지 않을 경우 상대적인 증가 적용

            BigDouble growthFactor = 1 + (scaledAmount / currentAmount);

            currencies[type] *= growthFactor;

        }

        else

        {

            currencies[type] += scaledAmount;

        }


        OnCurrencyChanged?.Invoke(type, currencies[type]);

        SaveData();

    }


    //재화 소모

    public bool TrySpendCurrency(CurrencyType type, BigDouble amount)

    {

        if (!currencies.ContainsKey(type) || currencies[type] < amount)

            return false;


        currencies[type] -= amount;

        OnCurrencyChanged?.Invoke(type, currencies[type]);

        SaveData();

        return true;

    }


    //재화 고정

    public void SetCurrency(CurrencyType type, BigDouble amount)

    {

        if (currencies.ContainsKey(type))

        {

            currencies[type] = amount;

        }

        else

        {

            Debug.Log("그런 재화는 없어");

        }

    }


    #endregion


    #region Multiplier


    private void InitializeMultipliers()

    {

        int length = System.Enum.GetValues(typeof(CurrencyType)).Length;

        additivePercentages = new double[length];

        multiplicativeMultipliers = new double[length];


        for (int i = 0; i < length; i++)

        {

            additivePercentages[i] = 0f;

            multiplicativeMultipliers[i] = 1f;  // 곱셈 배율의 기본값은 1

        }

    }


    public void AddAdditivePercentage(CurrencyType type, float additionalPercentage)

    {

        additivePercentages[(int)type] += additionalPercentage;

    }


    public void AddMultiplicativeMultiplier(CurrencyType type, float multiplier, bool isSet = false)

    {

        if (isSet)

            multiplicativeMultipliers[(int)type] = multiplier;

        else

            multiplicativeMultipliers[(int)type] += multiplier;

    }


    public BigDouble GetMultiplier(CurrencyType type)

    {

        return additivePercentages[(int)type];

    }


    #endregion


    private void SaveData()

    {

        foreach (CurrencyType type in System.Enum.GetValues(typeof(CurrencyType)))

        {

            // BigDouble 값을 문자열로 변환하여 저장

            PlayerPrefs.SetString($"Currency_{type}", currencies[type].ToString());


            // additivePercentages와 multiplicativeMultipliers 저장

            PlayerPrefs.SetString($"Additive_{type}", additivePercentages[(int)type].ToString());

            PlayerPrefs.SetString($"Multiplier_{type}", multiplicativeMultipliers[(int)type].ToString());

        }

        PlayerPrefs.Save();

    }


    private void LoadSavedData()

    {

        foreach (CurrencyType type in System.Enum.GetValues(typeof(CurrencyType)))

        {

            if (PlayerPrefs.HasKey($"Currency_{type}"))

            {

                // BigDouble.Parse를 사용하여 문자열을 BigDouble로 변환

                currencies[type] = BigDouble.Parse(PlayerPrefs.GetString($"Currency_{type}"));


                additivePercentages[(int)type] = double.Parse(PlayerPrefs.GetString($"Additive_{type}"), System.Globalization.CultureInfo.InvariantCulture);

                multiplicativeMultipliers[(int)type] = double.Parse(PlayerPrefs.GetString($"Multiplier_{type}"), System.Globalization.CultureInfo.InvariantCulture);

            }

            else

            {

                // 저장된 데이터가 없는 경우 기본값 설정

                currencies[type] = 0;

                additivePercentages[(int)type] = 0.0;

                multiplicativeMultipliers[(int)type] = 1.0;

            }

        }

    }


    private void OnApplicationQuit()

    {

        SaveData();

    }


    [SerializeField]

    CheckCurrency[] shower;

    private void Update()

    {

        for (int i = 0; i < shower.Length; i++)

        {

            CurrencyType type = (CurrencyType)i;  // enum의 순서대로 접근

            if (currencies.ContainsKey(type))

            {

                shower[i].SetCurrencyChecker(type.ToString(), currencies[type]);

            }

        }

    }

}


[System.Serializable]

public class CheckCurrency

{

    public string name;

    public BigDouble amount;


    public void SetCurrencyChecker(string name, BigDouble amount)

    {

        this.name = name;

        this.amount = amount;

    }

}


첫 개발 작품으로 증분형 게임 만들면서 여러가지 재화들을 이 스크립트 하나에서 다루고 있는데 질문할게 몇 가지 있어요

1. 각 재화마다 소모될지 안될지 설정을 할 필요가 있는데 지금 Enum과 딕셔너리로 다루고 있는 재화들을 클래스로 갈아엎어야 하나요?
2. 증분형 게임에 보통 순수 BigDouble을 사용하나요? 게임이 후반으로 가면 초반 재화들은 지수가 e1000은 넘을거 같은데 BigDouble은 e308까지 감당 가능하고
그 위의 숫자는 무한으로 취급한다길래 보통 한계를 고려하고 설계해서 쓰는지 아니면 다른 더 큰 수를 감당할 수 있는 시스템을 이용하는지 궁금합니다.
3. 이지세이브가 없어서 각각 재화랑 배율은 저렇게 저장하는데 작동 자체는 잘 되지만 보안 같은 외부적으로 괜찮은 코드인지 궁금합니다.