팀 프로젝트에서 아이템 - 인벤토리 관련을 만드는 역할을 맡았다.
우선 순서는 아이템을 다른 사람이 편하게 추가할 수 있는 DB를 만드는 것. .csv파일을 아이템 데이터베이스로 활용하여 다른 팀원들이 쉽게 수정할 수 있도록 만들어보자.
.csv파일은 여러가지로 만들 수 있지만, 역시 가장 편한것은 엑셀과 메모장이라고 생각한다. 간단하게 확인할 때는 메모장으로, 작성할 때는 엑셀로 쓰는 것이 편하다. 임시로 몇가지 아이템을 만들어서 .csv 파일로 저장해보자. 인코딩은 UTF-8을 사용할 것이다.
엑셀의 첫 번째(열 이름) 행에는 분류가 들어가고, 각각 ID에 의해 지정될 것이다. 그 뒤에는 아이템의 특성들이 나열되어있다. 작성한 이후 유니티의 Asset-Resources 폴더에 넣어주자.
※ 폴더 이름은 중요하다. Assets 다음으로 있는 Resources 폴더는 유니티에서 제공하는 Resources.Load 기능을 사용할 때 쓰인다.
이제 다른 사람들(기획)이 쉽게 아이템 정보를 수정할 수 있도록 엑셀파일을 넣어놓았으니, 나는 csv파일을 읽어서 사용하는 스크립트를 작성할 차례이다. .csv 파일을 읽어오는 스크립트이니 CSVReader라는 스크립트를 만들어주자.
public class CSVReader : MonoBehaviour
{}
이 CSVReader 스크립트는 다른 사람이 잘 만들어준 것이 있으나... 항상 그렇듯 공부를 겸하므로 직접 만들어보자.
우선적으로 필요한 것은 csv파일을 불러오는 것.
TextAsset data = Resources.Load(file) as TextAsset;
TextAsset이라는 형식으로 Resources 폴더에 있는 file을 가져온다. 이렇게 하면 csv파일을 가져올 수 있다.
var list = new List<Dictionary<string, object>>();
var lines = Regex.Split(data.text, LINE_SPLIT_RE);
가져온 csv 파일을 Dicticonary 형태로 list에 저장할 것이다. 그러기 위해서는 csv 파일을 줄 단위로 끊어 Split 해 줄 필요가 있다. 여기서 사용되는 Split 조건이 바로 LINE_SPLIT_RE.
static string LINE_SPLIT_RE = @"\r\n|\n\r|\n|\r";
해당하는 문자가 나오면 줄이 바뀌는 것으로 생각한다. 윈도우에서는 \r\n(CRLF), 리눅스에서는 \n(LF)이기에 다양한 줄바꿈 요소를 체크해야한다. \r\n, \n\r, \n, \r이 감지되면 다음 줄로 생각한다.
이렇게 나온 줄이 1 이하라면 아무 데이터도 없는 것이므로 return을 선언하고, 그게 아니라면 받아온 정보-행(Row)-을 쉼표 단위 데이터로 끊어줄 필요가 있다. 거기에 사용되는 것이 다시 SPLIT_RE.
static string SPLIT_RE = @",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))";
아래 문자가 등장하면 별개의 항목으로 취급하며 제외한다는 것이다. 조금 복잡하게 생겼는데, 이는 정규표현식이므로 어쩔 수 없다.
관련 정보가 필요하면 정규표현식을 따로 찾아봐야한다. 여기서의 정규 표현식은 큰 따옴표 " " 세트 안의 쉼표는 무시하고, 세트가 이루어지지 않는 바깥의 쉼표는 탐색하는 용도로 코드가 짜여졌다.
if (lines.Length <= 1)
{
return list;
}
//항목 단위로 끊기.
var header = Regex.Split(lines[0], SPLIT_RE);
for (var i = 1; i < lines.Length; i++)
{
var values = Regex.Split(lines[i], SPLIT_RE);
if (values.Length == 0 || values[0] == "")
{
continue;
}
}
첫 줄은 header로, 0번째 라인을 끊는다. 이 header들이 딕셔너리의 key 값이 될 예정이다.
그 이후 엑셀의 2번째 행부터는 정보가 들어가는데, 마찬가지로 SPLIT_RE를 통해 Split하고, 비어있다면 continue를 통해 다음 줄을 읽는다.
위에서 딕셔너리의 key 값이 될 예정이라고 했으니, 이제는 진짜 Dictionary를 선언할 시간이다.
데이터베이스는 List <Dictionary> 형태로, 데이터베이스의 한 줄 한 줄을 입력하는 코드인 것이다.
var entry = new Dictionary<string, object>();
for (var j = 0; j < header.Length && j < values.Length; j++)
{
string value = values[j];
value = value.TrimStart(TRIM_CHARS).TrimEnd(TRIM_CHARS).Replace("\\", "");
object finalvalue = value;
int n;
float f;
if (int.TryParse(value, out n))
{
finalvalue = n;
}
else if (float.TryParse(value, out f))
{
finalvalue = f;
}
entry[header[j]] = finalvalue;
}
list.Add(entry);
Header의 길이만큼(ID, Name, Power... 등의 갯수)만큼과 그 줄의 구성요소만큼을 읽을 때 까지 반복한다.
주목해야할 것은 Trim과 TryParse.
Trim은 static char[] TRIM_CHARS = { '\"' };로 선언된 TRIM_CHARS를 기반으로 문자열 앞 뒤의 "를 제거하고, Replace는 역슬래시와 공백문자를 제거하는데 사용된다.
그 이후 object로 선언한 finalvalue 값을 list에 더한다.
참고한 자료는 https://bravenewmethod.com/2014/09/13/lightweight-csv-reader-for-unity/#comment-7111
위의 링크처럼 완성되었다.
그럼 이제 이 아이템 베이스를 어떻게 가져다 써야할까?
나는 아이템에 관련한 부분을 담당할 Item Manager를 하나 만들어서 그 값을 읽어오도록 할 예정이다.
Manager는 하나만 존재하면 되니 싱글톤 패턴으로 만들고, 키를 눌러서 값을 제대로 읽어올 수 있는지 확인하는 코드를 작성해보자.
List<Dictionary<string, object>> data;
private void Start()
{
data = CSVReader.Read("ItemDataBase");
}
private int count = 0;
public void Update()
{
if(Input.GetKeyDown(KeyCode.A))
{
Debug.Log(("ID : " + data[count]["ID"] + "\t" +
"Name : " + data[count]["Name"] + "\t" +
"Description : " + data[count][eItemKeyColumns.Description.ToString()]));
text.text = ("ID : " + data[count]["ID"] + "\t" +
"Name : " + data[count]["Name"] + "\t" +
"Description : " + data[count]["Description"]);
count++;
if (count > 6) count = 0;
}
}
public enum eItemKeyColumns
{
ID,
Name,
Description
}
그리고 아이템의 열 이름은 언제든지 쉽게 바뀔 수 있고, 계속 직접 적어주면 오타때문에 버그가 날 수 있으므로 enum으로 선언해서 사용하도록 하자. 기존의 "ID" 대신 eItemKeyColumns.ID.ToString()이 들어가는 방식이다.
Debug.log와 Text 둘 다 잘 출력되는 것을 볼 수 있다.
다만 게임 내에서는 깨진 글자로 보이는데, 이는 기본적으로 한글을 지원하지 않는 폰트이기 때문이다. 이를 위해서는 한글을 지원하는 폰트를 따로 설치해야한다.(Indian Poker 개발과정 참고)
※ csv 파일의 인코딩은 UTF-8로 진행한다. 엑셀에 작성할 때는 ANSI로 열어서 작성하지만, Unity에서 기본적으로 UTF-8로 읽기에, 작성 이후 저장은 UTF-8.
'팀프로젝트' 카테고리의 다른 글
[完] 인벤토리, 아이템 제작 요약 (1) | 2024.01.21 |
---|---|
[05] 아이템 슬롯 상속, Create Table (0) | 2023.12.14 |
[04] 아이템 슬롯 상속, 퀵슬롯 (1) | 2023.12.14 |
[03] 인벤토리 기능 (0) | 2023.12.11 |
[02] 아이템 슬롯 (0) | 2023.11.28 |