Unity & C#

[유니티 C#] Json 저장 & 불러오기 너무 쉽게 구현하기

왼손잡이개발자 2021. 11. 12. 02:08

처음 유니티를 배우기 시작했을때 저장을 구현해야하는 순간이 찾아오면 어떻게 구현해야하는지 찾아보지도 않은채, 그저 '너무 어려울꺼같다' '지금 실력으로는 구현하기 힘들겠지?' 라고 무턱 겁부터 먹었던 기억이 있습니다. 그런데 지금 와서 생각해보면 왜 그렇게 겁을 냈을까? 라고 생각이 들고 왜 구현하려고 시도조차 하려고 하지 않았을까 후회가 되는 거같네요. 알고 보면 별거 아니고, 정말 쉽게 구현할 수 있는데 말이죠. 

 

 

저장을 할 때 저장파일 포맷으로 여러가지가 있는데 오늘은 Json 파일로 저장하는 방법에 대해서 알아보도록 하겠습니다. Json 형태로 저장하는게 어렵지는 않을까? 생각할 수도있는데 전혀 그렇지 않습니다. 너무 쉬워서 예전에 겁먹었던 것이 허무할 정도이죠... JsonUtility이라고 하는 UnityEngine에서 제공해주는 지리는 클래스가 다 알아서 해주거든요. 저희는 그저 ToJson(...) 과 FromJson<T>(...)이라고 하는 함수만 사용하면 됩니다.

 

저장&불러오기를 구현하기 위해서 저장과 불러오기가 필요한 상황을 하나 지어내 보겠습니다. 여러 캐릭터 중에 한 캐릭터를 선택해서 선택한 캐릭터가 저장되고, 다음에 불러오기를 했을 때 저장된 캐릭터가 불러와 지도록 하겠습니다.

 

저장을 하기 위해선 어떤 데이터가 저장되어야할지 정해야겠지요? 저는 캐릭터의 이름(name), 나이(age), 힘(power)을 저장하도록 하겠습니다. 이거를 SaveData라는 class를 만들어 변수들로 담아두겠습니다. (한가지 중요한 점은 SaveData 클래스가 꼭 Serializable 되게 해야합니다!. 클래스 윗쪽에 [System.Serializable]을 꼭 넣어주세요!)

	[System.Serializable]
	public class SaveData
	{
		public SaveData(string _name, int _age, float _power)
		{
			name = _name;
			age = _age;
			power = _power;
		}

		public string name;
		public int age;
		public float power;
		
	}

 

그리고 실제로 저장과 불러오는 함수를 포함하고 있는 SaveSystem이라는 이름의 static class를 만들겠습니다. 

public static class SaveSystem
	{
		private static string SavePath => Application.persistentDataPath + "/saves/";

		public static void Save(SaveData saveData, string saveFileName)
		{
			if(!Directory.Exists(SavePath))
			{
				Directory.CreateDirectory(SavePath);
			}

			string saveJson = JsonUtility.ToJson(saveData);

			string saveFilePath = SavePath + saveFileName + ".json";
			File.WriteAllText(saveFilePath, saveJson);
			Debug.Log("Save Success: " + saveFilePath);
		}

		public static SaveData Load(string saveFileName)
		{
			string saveFilePath = SavePath + saveFileName + ".json";
			
			if(!File.Exists(saveFilePath))
			{
				Debug.LogError("No such saveFile exists");
				return null;
			}

			string saveFile = File.ReadAllText(saveFilePath);
			SaveData saveData = JsonUtility.FromJson<SaveData>(saveFile);
			return saveData;
		}
	}

저는 Save(..) 함수에서 SaveData 와 string으로 저장파일이름을 파라미터로 받아서 저장을 하게 했습니다. 저장위치는 Application.persistantDataPath + "/saves/" 로 했습니다.(여기는 C:\Users\{컴퓨터유저이름}\AppData\LocalLow에서 찾을 수 있습니다.) 그리고 Load(...) 함수에선 저장파일의 이름을 파라미터로 넣어서 불러오게 만들었고 return value로 SaveData 형식으로 return 합니다. 그러면 실제로 이거를 실행하는 스크립트를 하나 만들어서 실행 코드를 보도록 하겠습니다. 

 

 public class SaveLoadController : MonoBehaviour
    {

        void Update()
        {
            if (Input.GetKeyDown("s"))
            {
                SaveData character = new SaveData("왼손잡이 개발자", 30, 100f);

                SaveSystem.Save(character, "save_001");
            }

            if(Input.GetKeyDown("l"))
			{
                SaveData loadData = SaveSystem.Load("save_001");
                Debug.Log(string.Format("LoadData Result => name : {0}, age : {1}, power : {2}", loadData.name, loadData.age, loadData.power));
			}
        }
    }

키보드 s를 누르면 저장(save)가 되게 했고, l을 누르면 불러오기(load)가 되게 했습니다. 먼저 SaveData 클래스 인스턴스를 하나 만들어주고 constructor 파라미터로 이름(string) - 왼손잡이 개발자 , 나이(int) - 30 , 힘(float) - 100f을 넘겨주었습니다. 그리고 SaveSystem.Save(...) 함수에 SaveData 클래스 인스턴스와 저장파일 이름("save_001")을 파라미터로 넘겨주고 저장을 실행시켰습니다. 

다음 키보드 l을 누르면 SaveSystem.Load(...)함수에서 저장파일 이름을 ("save_001")을 파라미터로 넘겨주어 저장 파일을 불러옵니다. 그리고 확인을 위해 loadData의 name, age, power를 log로 남겼습니다. 

 

위에 사진과 같이 console창에 log가 각 키마다 잘 찍히는 걸 확인할 수 있구요. 그리고 저장된 파일도 잘 생성됐는지 Application.persistantDataPath 에서 확인이 가능합니다

 

저장, 불러오기 너무 쉽죠? 왜 이렇게 시도도 안해보고 어렵다고 생각만 했을까요...참...