1.CSV
1-1. CSV란?

- 데이터베이스를 이룰 수 있는 가장 기본적인 파일.
- 각 행은 데이터의 레코드, 각 열은 데이터의 속성을 나타냄.
- ',' 또는 '\'를 통해서 데이터를 구분.
1-2. 유니티에서의 사용법.
using System.IO;
public struct WeaponData
{
public string index;
public string name;
public string attack;
public string defense;
public string description;
}
public class CsvParser : MonoBehaviour
{
public List<WeaponData> weapons = new List<WeaponData>();
private void Awake()
{
//persistentDathpath: 개인 로컬 저장소 경로 -> 게임 제작완료시
string persPath = Application.persistentDataPath;
// 프로젝트 경로 -> 게임 제작 중 사용
string path = Application.dataPath + "/Datatables";
if (Directory.Exists(path) == false)
{
Debug.Log("경로가 없습니다.");
return;
}
string[] files = Directory.GetFiles(path, "*.csv");
string file = File.ReadAllText(path + "/Datatable.csv");
string[] lines = file.Split("\n");
for (int i = 0; i < lines.Length; i++)
{
WeaponData weaponData = new WeaponData();
string[] values = lines[i].Split(',', '\t');
weaponData.index = values[0];
weaponData.name = values[1];
weaponData.attack = values[2];
weaponData.defense = values[3];
weaponData.description = values[4];
weapons.Add(weaponData);
}
}
}
- Application.persistentDatapath : 개인 로컬 저장소 경로
-> 게임 제작완료 후 배포 시 사용.
- Application.dataPath : 프로젝트 경로
-> 게임 제작 중 사용.
- Directory.Exists : 경로 확인.
- Directory.GetFiles(path) : 두번째 인자가 없는 경우, 그 경로에 있는 모든 파일을 가져오고, 두번째 인자가 있는 경우, 해당하는 인자에 대한 파일만 가져옴.
- File.ReadAllText : 특정 파일의 내용을 가져와 읽어옴.
- file.Split: 특정 문자를 기준으로 문자열 나눔.

- 꼭 CRLF로 해주기, LF같은 다른거로 하면 csv가 잘 안읽어와질수있음.
2. Json
2-1. 직렬화
- 데이터를 전송/저장하기 위해 데이터를 선형적으로 나열하는 것.
- 직렬화를 사용하면 게임 내 데이터 관리 및 게임 설정을 쉽게 관리할 수 있고, 직렬화를 네트워크상으로 보내는 데이터에 사용하기도 함.
2-2. Json

- 데이터 직렬화 포맷을 사용.
- key와 value 형식으로 데이터를 쌍으로 표현.
2-3. 유니티에서의 사용법.
using System.IO;
public class GameData
{
public string name;
public int level;
public float rate;
}
public class JsonTester : MonoBehaviour
{
[SerializeField] GameData gameData;
[ContextMenu("Save")]
private void Save()
{
string path = $"{Application.dataPath}/Save";
if(Directory.Exists(path) == false)
{
Directory.CreateDirectory(path);
}
string json = JsonUtility.ToJson(gameData);
File.WriteAllText($"{path}/save.txt", json);
}
[ContextMenu("Load")]
private void Load()
{
string path = $"{Application.dataPath}/Save/save.txt";
if(File.Exists(path) == false)
{
Debug.Log("불러올 세이브 파일 없음");
return;
}
string json = File.ReadAllText(path);
gameData = JsonUtility.FromJson<GameData>(json);
}
}
- [ContextMenu("name")] : name이름의 메뉴가 생성.
- Directory.CreateDirectory : 원하는 경로의 파일 생성.
-> 위 예시의 경우 Asset폴더안에 Save폴더 생성.
- JsonUtility.ToJson: 직렬화.
- File.WriteAllText($"path", json) : 해당 파일에 정보 입력.
- File.ReadAllText(텍스트path): 해당 경로에서 읽어옴.
- JsonUtility.FromJson : 역직렬화.
3. 스크립터블 오브젝트
3-1. ScriptableObject


- 유니티에서 데이터를 미리 저장해두고 사용할 수 있도록 하는 클래스.
- MonoBehaviour가 아닌 별도의 오브젝트로 관리 가능.
- MonoBehaviour와 다르게 에셋으로 저장이 됨.
3-2. 사용법
[CreateAssetMenu(menuName = "Quest/NormalQuest", fileName = "NormalQuest")]
public class Quest : ScriptableObject
{
public string title;
public string description;
public int exp;
public int gold;
public GameObject[] reWard;
}
3-3. 장점


- MonoBehaviour는 기본적으로 게임 오브젝트에 부착되어야 하며, 각 게임 오브젝트마다 독립적으로 인스턴스화되고, 각각의 MonoBehaviour가 메모리 내에 존재.
-> 이로 인해, 같은 데이터를 여러 번 복제해야 할 수 있습니다.
-> 반면, ScriptableObject는 게임 오브젝트와 독립적으로 존재할 수 있으며, 한 번 인스턴스화된 스크립터블 오브젝트를 여러 곳에서 참조 가능. 같은 데이터가 중복되지 않기 때문에 메모리 절약에 유리.
- 런타임에 변경할 필요가 없고, 공용Data의 경우 SO를 활용하면 좋다.
-> 변하지 않는 Data의 경우, Scriptableobject를 참조하여 Instantiate을 통해 복제한 데이터를 사용할 수 있으나, 이러면 기존의 SO 장점을 상쇄.
3-4. 활용방안 - 커맨드 패턴





- Scriptable Object를 상속받아 커맨드 패턴을 활용하여 알맞은 함수를 사용하는 것도 가능.
- 또는 객체지향원칙을 조금 무시하더라도 커맨드패턴이 아닌
단순히 public virtual void Use()를 통해, ItemData를 상속받아 자식클래스에서 재정의 하여 사용하는 법도 있음.
3-5. 활용방안 - 옵저버 패턴


- 이벤트를 활용한 옵저버 방식도 가능하다.
-> ScriptableObject 자체가 유일무이하기 때문에 싱글톤 패턴 대신에 ScriptableObject를 사용하여 구현이 가능하다.
-> 예로 싱글톤패턴을 적용한 클래스에 이벤트를 구현하고, 다른 Observer에 이벤트를 연결하는 것보단, 싱글톤패턴을 사용하지 않고 ScriptalbeObject를 사용하는것이 통합테스트면에서도 이점을 가지고 올 수 있다.
3-6. 주의점
- 에디터에서는 스크립터블 오브젝트를 언제나 생성해서 데이터 저장이 가능하지만, 배포된 빌드에서는 스크립터블 오브젝트를 새로 생성할수 없어 기존의 스크립터블 오브젝트의 데이터만을 사용
- 에셋파일형식으로 저장되기때문에, 에셋번들로 빌드하고 배포하는 방식으로 게임 업데이트 가능.
- 게임 빌드에 포함되기에 사용자가 설치된 게임data를 수정가능. 싱글겜에서는 크게 영향이 없을수있으나 멀티겜에서는 영향이 크므로 중요한 data를 스크립터블오브젝트로 저장하면 안됨
- SO를 참조하고 내부에서 새로운 SO를 Instantiate를 하는 방식은 기존의 SO의 장점을 상쇄하기 때문에, 가능하면 불변하는 Data와 관련해서 SO로 관리하는것이 좋음