다양한 기록

[Fortess Craft] 스프레드 시트와 연결 본문

유니티 엔진/Fortress Craft

[Fortess Craft] 스프레드 시트와 연결

라구넹 2025. 2. 5. 21:56

이런식으로 필요한 데이터들이 스프레드 시트로 관리됨

 

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using System.Collections.ObjectModel;

namespace Agit.FortressCraft {

    public static class GoogleSheetManager
    {
        public static List<CommanderData> commanderDatas = new List<CommanderData>();
        public static List<UnitData> unitDatas = new List<UnitData>();

        //link change : edit ~ -> export?format=tsv

        private static readonly List<string> _urls = new List<string>
        {
            "커맨더 시트 링크",
            "유닛 시트 링크"
        };

        public static readonly ReadOnlyCollection<string> Urls = new ReadOnlyCollection<string>(_urls);

        public static IEnumerator Loader()
        {
            List<string> data = new List<string>();
            foreach (var url in Urls)
            {
                UnityWebRequest www = UnityWebRequest.Get(url);
                yield return www.SendWebRequest();

                data.Add(www.downloadHandler.text);
                
            }

            if (data[0] != null) 
                ParseCommanderData(data[0]);
            if (data[1] != null)
                ParseUnitData(data[1]);
            foreach(string d in data)
            {
                Debug.Log(d);
            }
        }
        private static void ParseCommanderData(string data)
        {
            string[] lines = data.Split('\n');
            for (int i = 1; i < lines.Length; i++) 
            {
                string[] fields = lines[i].Split('\t');
                if (fields.Length < 5) 
                {
                    Debug.LogError($"Line {i} has insufficient fields: {fields.Length} fields found.");
                    continue;
                }
                try
                {
                    CommanderData commanderData = new CommanderData()
                    {
                        CommanderType = fields[0],
                        Level = ParseInt(fields[1]),
                        NeedExp = ParseInt(fields[2]),
                        HP = ParseFloat(fields[3]),
                        MP = ParseFloat(fields[4]),
                        Attack = ParseFloat(fields[5]),
                        AttackSpeed = ParseFloat(fields[6]),
                        AttackDelay = ParseFloat(fields[7]),
                        Defense = ParseFloat(fields[8]),
                        MoveSpeed = ParseFloat(fields[9]),
                        HealPerSecond = ParseFloat(fields[10]),
                    };
                    commanderDatas.Add(commanderData);
                }
                catch (FormatException e)
                {
                    Debug.LogError($"FormatException on line {i}: {e.Message}");
                }
                catch (OverflowException e)
                {
                    Debug.LogError($"OverflowException on line {i}: {e.Message}");
                }
            }
        }
        private static void ParseUnitData(string data)
        {
            string[] lines = data.Split('\n');
            for (int i = 1; i < lines.Length; i++) 
            {
                string[] fields = lines[i].Split('\t');
                if (fields.Length < 11) // enough field? 
                {
                    Debug.LogError($"Line {i} has insufficient fields: {fields.Length} fields found.");
                    continue;
                }

                try
                {
                    UnitData unitData = new UnitData()
                    {
                        Level = ParseInt(fields[0]),
                        UpgradeCost = ParseInt(fields[1]),
                        HP = ParseFloat(fields[2]),
                        MP = ParseFloat(fields[3]),
                        Attack = ParseFloat(fields[4]),
                        AttackDelay = ParseFloat(fields[5]),
                        Defense = ParseFloat(fields[6]),
                        MoveSpeed = ParseFloat(fields[7]),
                        SpawnDelay = ParseFloat(fields[8]),
                        CostReward = ParseInt(fields[9]),
                        ExpReward = ParseInt(fields[10]),
                    };
                    unitDatas.Add(unitData);
                }
                catch (FormatException e)
                {
                    Debug.LogError($"FormatException on line {i}: {e.Message}");
                }
                catch (OverflowException e)
                {
                    Debug.LogError($"OverflowException on line {i}: {e.Message}");
                }
            }
        }
        private static int ParseInt(string input)
        {
            if (int.TryParse(input, out int result))
            {
                return result;
            }
            throw new FormatException($"Unable to parse '{input}' as integer.");
        }

        private static float ParseFloat(string input)
        {
            if (float.TryParse(input, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out float result))
            {
                return result;
            }
            throw new FormatException($"Unable to parse '{input}' as float.");
        }

        public static CommanderData GetCommanderData(int level, JobType jobType)
        {
            if (level > 15) level = 15;

            int offset = 0;

            switch (jobType)
            {
                case JobType.Warrior:
                    offset = -1;
                    break;
                case JobType.Magician:
                    offset = 14;
                    break;
                case JobType.Archer:
                    offset = 29;
                    break;
            }

            return GoogleSheetManager.commanderDatas[level + offset];
        }

        public static UnitData GetUnitData(int level)
        {
            return GoogleSheetManager.unitDatas[level - 1];
        }
    }

    [System.Serializable]
    public class CommanderData
    {
        public string CommanderType;
        public int Level;
        public int NeedExp;
        public float HP;
        public float MP;
        public float Attack;
        public float AttackSpeed;
        public float AttackDelay;
        public float Defense;
        public float MoveSpeed;
        public float HealPerSecond;
    }

    [System.Serializable]
    public class UnitData
    {
        public int Level;
        public int UpgradeCost;
        public float HP;
        public float MP;
        public float Attack;
        public float AttackDelay;
        public float Defense;
        public float MoveSpeed;
        public float SpawnDelay;
        public int CostReward;
        public int ExpReward;
    }
}

싱글톤으로 매니저 만들고, 데이터 로드하고 파싱

 public static CommanderData GetCommanderData(int level, JobType jobType)
 {
     if (level > 15) level = 15;

     int offset = 0;

     switch (jobType)
     {
         case JobType.Warrior:
             offset = -1;
             break;
         case JobType.Magician:
             offset = 14;
             break;
         case JobType.Archer:
             offset = 29;
             break;
     }

     return GoogleSheetManager.commanderDatas[level + offset];
 }

 public static UnitData GetUnitData(int level)
 {
     return GoogleSheetManager.unitDatas[level - 1];
 }

시트 오프셋에 따라 위 두 함수가 구현되고,

외부에서는 커맨더나 유닛의 레벨만 넣으면 데이터를 얻을 수 있음

 

public void SetMaxHPByLevel(int level, JobType jobType)
{
    MAX_HEALTH = GoogleSheetManager.GetCommanderData(level, jobType).HP;
    Debug.Log("Max HP: " + MAX_HEALTH);
}

public void SetAttack(int level, JobType jobType)
{
    AttackDamage = GoogleSheetManager.GetCommanderData(level, jobType).Attack;
}

public void SetDefenseHPByLevel(int level, JobType jobType)
{
    Defense = GoogleSheetManager.GetCommanderData(level, jobType).Defense;
}

public float GetNeedExpByLevel(int level, JobType jobType)
{
    return GoogleSheetManager.GetCommanderData(level, jobType).NeedExp;
}

Player 코드의 일부

매니저에서 데이터 빼내서 Set하거나 Get하여 사용