Unity: 스프레드시트를 이용해보자 - 2

이재형·2024년 7월 8일
0
post-thumbnail
post-custom-banner

Unity 공부

스프레드시트를 이용해보자

진행 전 : 2번째 이므로 문제 3단계는 적지 않음

1. Enemy의 스탯정보를 생성

[System.Serializable]
public class EnemyStatus
{
    public string name;
    public MonsterType monsterType;
    public int health;
    public int attack;
    public float attackSpeed;
    public float attackRange;
    public AttackType attacType;
    public float moveSpeed;
    public int soul;
    public int exp;
}

public enum AttackType
{
    Melee,
    Ranged,
    Dual
}

public enum MonsterType
{
    Normal,
    Rare,
    Named,
    Boss
}

직렬화로 System.Serializable을 추가하여 생성한다.


2. 위의 EnemyStatus의 정보를 저장할 변수 및 시트에 저장할 변수 선언

public List<EnemyStatus> enemys;

private Dictionary<Type, string> sheetDatas = new Dictionary<Type, string>();

public void Awake()
{
    sheetDatas.Add(typeof(EnemyStatus), GetCSVAddress(adress, range, sheetID));
}

enemys라는 변수에 각 Enemy의 정보를 저장한 List 변수를 선언하고 시트에서 불러올 주소인 딕셔너리 변수에 클래스변수 Type과 주소인 string으로 선언한다.


3. 선택한 Type에 따라서 정보를 분류

public IEnumerator LoadData()
{
    List<Type> sheetTypes = new List<Type>(sheetDatas.Keys);

    foreach (Type type in sheetTypes)
    {
        UnityWebRequest www = UnityWebRequest.Get(sheetDatas[type]);
        yield return www.SendWebRequest();

        // 딕셔너리의 value 값 변경
        sheetDatas[type] = www.downloadHandler.text;

        if (type == typeof(EnemyStatus))
        {
            enemys = GetDatasAsChildren<EnemyStatus>(sheetDatas[type]);

            foreach (EnemyStatus enemyStatus in enemys)
            {
                // 저장된 enemy 정보들 처리
            }
        }
    }
}

원래 value값이 주소였는데 가져온 텍스트의 정보로 value값을 변경해준다.


4. 출력한 string형 데이터의 내용을 Split처리

위의 사진 처럼 열을 나누는 \t와 행을 나누는 \n으로 잘라서 string[]변수인 datas에 추가

List<T> GetDatasAsChildren<T>(string data)
{
    List<T> dataList = new List<T>();

    // 셀의 행의 값을 배열에 저장 (농부, 냥꾼 등 각 내용을 배열에 저장한다는 뜻)
    string[] splitedData = data.Split('\n');

    // 저장한 배열의 값에 접근
    foreach (string element in splitedData)
    {
        // 해당 객체의 정보를 배열에 저장(농부의 체력, 공격력 등 내용을 배열에 저장)
        string[] datas = element.Split('\t');
        dataList.Add(GetData<T>(datas, datas[0]));
    }

    return dataList;
}

5. split한 문자열을 타입을 확인하여 변경처리

FieldInfo[] fields = typeof(T).GetFields()는 제네릭 T에 있는 필드들의 정보를 가져오는 것인데 순서대로 필드를 가져오기 때문에 시트의 내용과 T에 넣을 클래스의 순서가 맞아야한다.
1. BindingFlags.Public: public인 필드
2. BindingFlags.NonPublic: public을 제외한 필드
3. BindingFlags.Instance: 필드에 있는 instance
4. BindingFlags.static: 필드에 있는 static

T GetData<T>(string[] datas, string typeName = "")
{
    object data;

    // childType이 비어있거나 그런 Type이 없을 때
    if (string.IsNullOrEmpty(typeName) || Type.GetType(typeName) == null)
    {
        data = Activator.CreateInstance(typeof(T));
    }
    else
    {
        data = Activator.CreateInstance(Type.GetType(typeName));
    }

    // 클래스에 있는 변수들을 순서대로 저장한 배열 (순서대로 진행이 되므로 스프레드시트와 클래스의 순서가 같아야함)
    FieldInfo[] fields = typeof(T).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

    for (int i = 0; i < datas.Length; i++)
    {
        // 필드의 내용을 인스턴스 data에 저장
        try
        {
            // string > parse
            // EnemyStatus에 선언한 변수들의 순서대로 타입을 확인
            Type type = fields[i].FieldType;

            if (string.IsNullOrEmpty(datas[i])) continue;

            if (type == typeof(int))
                fields[i].SetValue(data, int.Parse(datas[i]));

            else if (type == typeof(float))
                fields[i].SetValue(data, float.Parse(datas[i]));

            else if (type == typeof(bool))
                fields[i].SetValue(data, bool.Parse(datas[i]));

            else if (type == typeof(string))
                fields[i].SetValue(data, datas[i]);

            // enum
            else
                fields[i].SetValue(data, Enum.Parse(type, datas[i]));
        }

        catch (Exception e)
        {
            Debug.LogError($"SpreadSheet Error : {e.Message}");
        }
    }

    return (T)data;
}

필드의 내용을 순서대로 받아서 타입을 확인하여 타입을 SetValue로 변경을 하여 모든 필드의 타입을 변경해주고 반환을 합니다.


6. (3)번의 내용으로 넘어가서 남은 처리

if (type == typeof(EnemyStatus))
        {
            enemys = GetDatasAsChildren<EnemyStatus>(sheetDatas[type]);

            foreach (EnemyStatus enemyStatus in enemys)
            {
                // 저장된 enemy 정보들 처리
            }
        }

이제 정보를 foreach로 각 정보를 enemyStatus에 넣어서 각 정보를 처리를 한다.

정리

배운 내용

1.

해결 못한 문제

1. 없음

문제점

1. 없음

profile
한국사람
post-custom-banner

0개의 댓글