[Unity] Electricity (12)

suhan0304·2024년 6월 16일

유니티-Electricity

목록 보기
12/18
post-thumbnail

preview Link : https://velog.io/@suhan0304/Unity-Electricity-11
gitHub Link : https://github.com/suhan0304/Electricity


이제 맵 데이터를 Json으로 저장하는 것부터 해보자.

JSON Save

MapData.cs

using UnityEngine;
using System.Collections.Generic;

[System.Serializable]
public class MapData
{
    public Vector3 startNode; // StartNode의 좌표
    public Vector3 endNode; // EndNode의 좌표
    public List<Vector3> nodePositions; // 모든 노드들의 좌표
    public Dictionary<int, int> blockInventory; // 블록 타입별 보유 개수 (예: {1: 2, 3: 4})

    public MapData(Vector3 start, Vector3 end)
    {
        startNode = start;
        endNode = end;
        nodePositions = new List<Vector3>();
        blockInventory = new Dictionary<int, int>();
    }
}

일단 MapData를 구조화 시킨 다음에 현재 Map의 정보를 MapData에 담은 다음에 json 형식으로 내보내는 것을 구현해보자.

Map.cs

using UnityEngine;
using System.Collections.Generic;

[System.Serializable]
public class Map : MonoBehaviour
{
    public GameObject fieldObject;

    public int level;
    public Vector3 startNode; // StartNode Position
    public Vector3 endNode; // EndNode Position
    public List<Vector3> nodePositions; // all Nodes Position
    public Dictionary<int, int> blockInventory; // blockInventrory<BlockType(num), blockCounts> {1: 2, 3: 4})

    void Start() {
        SetMapData();
    }

    void SetMapData() {
        fieldObject = GameManager.Instance.field;
        if (fieldObject != null) {
            foreach (Transform child in fieldObject.transform) {
                if(child.CompareTag(GameManager.Instance.NodeTag)) {
                    if(child.name == GameManager.Instance.startNode) {
                        startNode = child.position;
                    }
                    else if(child.name == GameManager.Instance.endNode) {
                        endNode = child.position;
                    }
                    else {
                        nodePositions.Add(child.position); 
                    }
                }
            }
        }
    }
}

위와 같이 구현해서 Map 인스턴스를 생성하면 자동으로 Start, End, Nodes의 정보들이 리스트에 담기도록 해주었다. 이제 Map을 불러온 다음에 json으로 내보내보자.

JsonSerialize.cs

using UnityEngine;
using System.IO;

public class JsonSerialize
{
    public static void SaveMapDataToJson(Map map) {
        string fileName = Path.Combine(Application.dataPath + "/MapData/mapData_Level1.json");

        // file already exist
        if (File.Exists(fileName)) {
            File.Delete(fileName); // delete existing file
        }

        MapData mData = new MapData(map); // set MappData

        string json = JsonUtility.ToJson(mData); // Convert MapData to Json

        File.WriteAllText(fileName, json);
    }
}

Serialize(직렬화)? : 객체를 '연속된' Byte 나 String 으로 변환하는 과정을 의미한다. Object는 메모리에 올라와 있지만 파일로 저장하거나 통신을 위해서는 Byte 나 String 형식으로 바꿔줄 필요가 있다.


save Data가 잘되나 확인하기 위해 버튼을 만들어 데이터 저장을 수동으로 해보자

GameManagerEditor.cs

using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(GameManager))]
public class GameManagerEditor : Editor
{
    public override void OnInspectorGUI()
    {
        DrawDefaultInspector();

        GameManager gameManager = (GameManager)target;
        if (GUILayout.Button("Save MapData"))
        {
            gameManager.SetMapData();
        }
    }
}

이제 GameManager에 SetMapData 메소드를 만들어준 후에 버튼을 눌러보자.

이제 이걸 json으로 Sava 해보자. SaveMapData Button을 누르니 아래와 같이 파일이 생겼다!

{"level":0,"startNode":{"x":0.0,"y":1.0,"z":0.0},"endNode":{"x":25.0,"y":1.0,"z":10.0},"nodePositions":[]}

ToJson의 prettyPrint 파라미터를 true로 넘겨줘서 json 파일의 줄바꿈을 깔끔하게 처리할 수 있다.

배열이 저장이 안 되는 오류가 발생했다. ToJson 으로는 List<Vector3>를 직렬화하는게 어렵다고 해서 다른 방법을 찾아보았다. Wrapper로 map을 한번 감싸서 문제를 해결했다.

JsonUtility의 가장 큰 단점이 배열을 받을 수 없다는 것인데 다음과 같이 JsonObject를 감싸는 Wrapper 클래스를 따로 만들어서 문제를 해결할 수 있다.
출처 : https://debuglog.tistory.com/36

startNode, endNode, vector3List까지 잘 저장되는 모습, 성공이다!
완성된 코드는 아래와 같다.

JsonSerialize.cs

using UnityEngine;
using System.Collections.Generic;
using System.IO;



public class Vector3ListWrapper
{
    public int level;
    public Vector3 startNode;
    public Vector3 endNode;
    public List<Vector3> vector3List;

    public Vector3ListWrapper(Map map, List<Vector3> vector3List)
    {
        level = map.level;
        startNode = map.startNode;
        endNode = map.endNode;
        this.vector3List = vector3List;
    }
}

public class JsonSerialize
{
    public static void SaveMapDataToJson(Map map) {
        string fileName = Path.Combine(Application.dataPath + "/MapData/mapData_Level1.json");

        // file already exist
        if (File.Exists(fileName)) {
            File.Delete(fileName); // delete existing file
        }

        MapData mData = new MapData(map); // set MappData
    
        // Convert MapData to Json
        string json = JsonUtility.ToJson(new Vector3ListWrapper(map, map.nodesPosition), true);

        Debug.LogWarning(json);

        File.WriteAllText(fileName, json);

        Debug.Log("Finish - Save Map Data");
    }
}

JSON Load

이제 로드를 해보자.


Tag & Name

원래는 게임 매니저 스크립트 안에 그나마 하드코딩 막아보겠다고 Tag, Name 이라는 변수를 만들어서 저장을 했었는데 이거를 아예 하나로 빼는게 다른 스크립트에서도 굳이 게임 매니저를 통한 싱글톤 패턴 접근이 아니어도 사용 가능하도록 업데이트해주었다.

public static class Names {
    
    public const string startNode = "StartNode";
    public const string endNode = "EndNode";
    public const string BulbName = "Bulb";
}
public class Tags {
    public const string startTag = "startPoint";
    public const string endTag = "endPoint";
    public const string blockTag = "block";
    public const string NodeTag = "node";
}

모든 스크립트에서 Tag, Name 참조 부분을 수정해주었다.


profile
Be Honest, Be Harder, Be Stronger

0개의 댓글