언리얼 엔진 4 문서에서 '데이터 주도형 게임 플레이 요소' 라는 글을 읽고

따라해보다가 설명된 것 치고는 은근히 어물쩡(?) 설명되있어서 

사람을 몇 시간씩 구글링하게 만들게 한다ㅡㅡ+...


열받아서 나처럼 헤매는 이가 없도록 포스팅을 하게 됐다.



그래서 오늘 할 것은 

".csv 파일의 데이터를 언리얼 엔진4 에서 사용할 수 있도록 DataTable 오브젝트를 생성하는 가이드 라인" 을 

작성해 보겠다. 

+ 팁으로 일부 버그에 대한 핸들링도 언급하겠다.


다소 영문 문서를 그대로 번역한 느낌의 말투가 있더라도 양해를(__)

제가 직접 해본 것을 기반으로 포스팅한 거라 "반드시 이렇다!" 라는 건 아닙니다!




언리얼 엔진4에서 사용되는 DataTable 의 유형은 크게 2 가지이다.


1) Data Table

어떤 데이터 타입이든 자유롭게 정의할 수 있다. 

ex ) int, string, TAssetPtr<UTexture>, 기타 등등.


2) Curve Table

부동소수점 실수 타입의 데이터만 정의할 수 있고 곡선 상의 보간에 특화된 테이블이다.


- Curve 는 게임 내의 밸런스나 기술/능력에 대한 특성 조절에 유용하게 사용될 수 있다고 한다.

예를 들어 게임 난이도 설정에 따라 HP 가 달라지는 몬스터가 있는 경우

100 ~ 10,000 범위의 HP Curve 를 선형이든 큐브형이든 어떤 방식으로 정의한 후에,

어려움의 난이도 에서 몬스터의 HP 값을 그 Curve 의 최소 / 최대 값 의 75% 정도에서

따오면 된다.

(Curve Table 의 경우, 자세한 내용을 다루는 것은 못봐서 이 정도로만 언급하겠다)




그러면 아까 위에서 말한 가이드 라인으로 돌아와서

크게 5가지 스텝으로 나누어 설명하도록 하겠다.


1. .csv 파일 생성

2. FTableRowBase 를 상속받는 구조체를 생성

3. 코드 빌드 후 언리얼 엔진 재실행

4. 컨텐츠 브라우저에 .csv 파일을 드래그앤드롭 하면 DataTable 오브젝트 생성

5. 블루 프린트나 코드에서 4. 의 오브젝트를 이용해 데이터에 접근 가능




1. 언리얼 엔진에 import 할 .csv 파일을 생성한다.


다음과 같이 엑셀에서 데이터를 만든 후, 저장할 때 .csv 파일을 생성해도 된다.

A1 은 비워두라고 되어있지만 굳이 쓰고 싶다면 써도 큰 문제는 없다.


왜냐하면 첫 번째 컬럼 값들은 Row ID 를 나타냄으로서 

데이터 테이블에서 Row 를 구분하기 위해 반드시 있어야 하는 기본적인 아이라 

언리얼 엔진4에서 이 파일을 import 할 때, 첫 번째 컬럼은 건너뛰어 버리기 때문이다.

(관련 링크 : CreateTableFromCSVString

https://docs.unrealengine.com/latest/INT/API/Runtime/Engine/Engine/UDataTable/CreateTableFromCSVString/index.html )


내가 만든 샘플 데이터(.csv)들은 다음과 같이 생겼다.




2. FTableRowBase 를 상속받는 구조체를 생성한다.



언리얼 엔진에서 프로젝트를 열고, 코드를 추가해준다. 

이 때 주의해야 할 점은 None 이 아니라 언리얼 엔진에서 제공하는 클래스를 반드시 상속받도록 하자.

안 그러면 차후 빌드할 때 꽤나 골치 아파진다.. 그냥 Dummy 클래스 하나 만든다고 생각하자.


저 같은 경우에는 'Show All Classes' 에 체크하고 Engine 클래스를 상속 받았습니다.

별 뜻 없습니다. 단지 None 으로 하고 구조체만 달랑 정의했다가 -매우 - 피봤기 때문에ㅠ_ㅠ

누군가가 "이렇게 하니까 되던데요" 라고 하는 코드를 보고 저 클래스를 상속 받았을 뿐.


Engine 클래스가 아니더라도 Actor 를 받아도 되고 상관 없습니다.

구조체 정의하기 전에 언리얼 엔진의 클래스를 반드시 상속 받는 Dummy 클래스를 만드는 게 포인트.



저 같은 경우 빈 프로젝트에서 데이터 테이블을 생성하고 있었는데,

찾아보니 이 문제(?)를 해결 하기 위해서는 프로젝트에 반드시 언리얼 엔진에서 

상속받은 클래스가 적어도 1개 이상 있어야 한다고 한다.

(관련 링크 : https://answers.unrealengine.com/questions/71182/can-not-derivate-from-struct-ftablerowbase.html )



클래스를 만들었으면 구조체를 정의하는데 그 안에

1.에서 만든 데이터 필드들의 이름과 동일하게 변수들을 작성해주면 된다.


내가 만든 데이터들을 기반으로 구조체를 작성해 본 결과는 다음과 같다.

언리얼 엔진에서 Engine 클래스를 상속받은 MyDataAsset 이라는 클래스를 생성했고,

아래 코드는 MyDataAsset.h 에 작성하였다. LevelUpdata 라는 구조체를 만들었다.



아까 위에서 보여준 .csv 파일에서 첫번째 셀의 값에 Name 이라는 값을 넣어주었지만

코드에서는 적어주지 않았다. 적어도 되고 안 적어도 되는 듯 싶지만...


언리얼 엔진4 문서에서는 생략하길래 그냥 나도 생략해버렸다. 귀찮아서.


여기서 포인트는 구조체가 FTableRowBase 를 상속받았다는 점.

아, 참고로 언리얼 엔진 구조체 내에는 함수를 정의할 수 없다고 한다. 

(상당히 내겐 충격적이었음_-_ .......... 구조체 내에 함수 정의를 못 해서

밑에 다룰 버그 관련 내용에서 살짝 귀찮게 됨)



코드 따라서 입력하기 귀찮으신 분들은 포스팅 맨 아래 참고 링크들

따라가셔서 ctrl + c,v 하시면 됩니다~




3. 빌드를 하고 언리얼 엔진을 재실행 시킨다.


주의해야 할 점은 빌드 하기 전에는 반드시 언리얼 엔진을 종료시켜야 한다.

안 그러면 LNK 에러를 미친 듯이 뿜어낼 수 있다. (정확한 이유는 잘 모르겠음)


엔진 종료 -> 빌드 -> 엔진 재실행


순서로 가자.




4. 엔진의 컨텐츠 브라우저에서 1. 에서 만든 .csv 파일을 드래그앤드롭 한다.



이 때, 다음과 같은 다이얼로그 박스가 하나 나올 것이다.



3. 에서 정의한 구조체인 LevelUpData 가 보일 것이다.

만약 2.에서 언리얼 엔진으로부터 상속 받은 클래스가 없다면 저 망할 Row Type 에 

내가 정의한 구조체가 뜨지 않는, 짜증나는 현상의 연속을 보게 될 것이다. -> 이것때문에 삽질 겁나 함.



아무튼 여기까지 Import 과정을 모두 마쳤으면 위의 스샷처럼 콘텐츠 브라우저에

'DataTable' 이라는 초록색 오브젝트가 생긴 것을 볼 수 있다 :-)


오브젝트를 더블 클릭하면,


요렇게 이쁘게 나오는 것을 볼 수 있다.


참고로 중간에 .csv 파일의 데이터가 수정되었다면 

엔진 쪽에서 만든 오브젝트를 우클릭 -> Reimport 하면 변경된 데이터를 볼 수 있다.



그런데 ! 주의해야할 점을 알려준다면 

위와 같이 어떤 파일의 상대주소를 데이터로 넣었을 때, 제대로 안 뜨는 경우가 있다.


나의 경우 어떤 삽질을 했냐면...


엑셀 파일에서 "Texture2d'/Game/Textures/AchievementIcon2'" 라고 입력을 한 뒤에

.csv 파일로 변환해서 그 파일을 열어보면 어처구니 없게도 ㅡ_ㅡ

양쪽에 큰 따옴표가 2개씩 더 붙어서 나오는 현상이 있었다.

이렇게. -> """Texture2d'/Game/Textures/AchievementIcon2'"""


저런 경우에는 언리얼 엔진에서 import 한 데이터가 None 으로 뜨게 되버린다.


또는 큰 따옴표를 빼먹고 Texture2d'/Game/Textures/AchievementIcon2' 라는 데이터가

.csv 파일에 저장되어있을 때, import 하면 데이터가

Texture2d' 까지 밖에 안 보이는 현상이 있었다.


위 스샷 처럼 정확한 주소를 보이게 하려면 .csv 파일을 열어봤을 때, 데이터가

"Texture2d'/Game/Textures/AchievementIcon2'" 와 같이 정확히 한쌍의 큰 따옴표만 감싸고 있어야 한다는 점.


그러니 엑셀에서 큰 따옴표를 사용해 데이터를 저장할 때는 주의하자 ! !



참고로 아래는 언리얼 엔진 문서에서 발췌한 내용이다.

The double quotes around the asset type are important for the property importing pipeline. Without them, the text is imported as Texture2d'.





5. 블루프린트나 코드 상에서 4.에서 생성한 오브젝트에 접근해보자.


여기서 중요한 건, 블루프린트에서 데이터에 접근할 때 짜증나는 버그가 존재한다.

차후 엔진 측에서 고쳐줄 지는 모르겠지만 지금 언리얼 엔진 4.4 버전 상에서는 아직도 존재한다.


1) 블루프린트에서 DataTable 오브젝트에 접근 하기


무슨 버그가 있는지 일단 살펴보겠다.

아래에 보면 개발자가 정의한 데이터 테이블에 있는 데이터에 접근하기 위해 

"Get Data Table Row (DataTable Object 이름)" 라는 노드가 존재한다.

이게 문제다.



빨간색으로 'X' 표시 되어있는 부분이 문제의 버그다.

막상 블루프린트 작성할 때는 멀쩡히 잘 연결되다가 언리얼 엔진을 종료하고

다시 이 프로젝트를 열면 저기 표시되어 있는 링크 부분이 사라지게 되는 버그가 발생한다.

그래서 데이터에 접근이 안 되서 컴파일 할 수 없다고 난리다. 


(데이터 테이블의 초기화 문제였나? 암튼 그런 쪽으로 뭔가 버그가 있는 듯 했다.

구글링했을 때 영문으로 뭐라고 나와있었는데 이해할 수 없었다. 아시는 분은 방명록에 남겨주시면 ㄳㄳ (__)

자세한 링크는

https://answers.unrealengine.com/questions/67457/get-data-table-row-bug.html )


결국, 문제의 'Get Data Table Row' 노드를 사용할 수 없다.

그러니 우회하는 방법으로 데이터에 접근하자. 꽤 간단하게 해결되는 문제다.



여기서부터 내가 구글링의 도움을 받아 실험한 결과를 토대로 작성한 가이드 라인이다.

정답은 아니고 '이런 식으로 해결 할 수 있다고 하네요' 정도로만 읽어주시면 감사하겠습니다 :-)



① 언리얼 엔진에서 코드를 추가한다.

내 경우에는 Actor 를 부모 클래스로 상속받아 'DummyActor' 클래스를 생성했다.



② DummyActor.h 에 다음과 같이 작성해준다.



사실 나는 아까 선언했던 LevelUpData 구조체 안에 getTableRow() 함수를 넣으려고 했지만 

위에서 이미 언급했듯이 구조체 안에 함수 선언을 할 수가 없다...ㄱ-....아놔..


그래서 따로 울며 겨자먹기로 새로 클래스를 만들어 위와 같이 코드를 작성해주었다.



③ DummyActor.cpp 에 다음과 같이 작성해준다.



빨간색 네모 박스에 있는 코드가 핵심이다.



④ 언리얼 엔진을 종료하고 빌드한 후, 엔진을 재실행하자.



⑤ 내 경우에는 게임이 Play 될 때 좌측 상단에 데이터를 출력하는 걸 테스트하고 싶었다.

그래서 잘은 모르지만(?) : 참고로 필자는 언리얼 엔진4 써 본지 얼마 안 된 조금 멍청한 초보다.

GameMode 를 상속받아 블루프린트를 생성하였다.



⑥ 블루프린트에서 DataTable Row Handler 타입의 변수를 하나 생성해 

Default value 에서는 4.에서 생성한 Data Table 오브젝트에 연결 할 수 있다.

Row Name 은 데이터 테이블에서 행을 구분해주는 첫번째 컬럼을 말한다. 가져오길 원하는 RowID 값을 선택하면 된다.


아까 정의한 getTableRow 함수를 가져와야 하니 DummyActor 변수도 생성해주자.



⑦ 다음과 같이 데이터에 접근할 수 있다.

원하는 데이터에 접근해 마음대로 지지고 볶고 하시면 됩니다. 잘 안 보이시면 이미지 클릭.





여기까지 블루프린트에서 DataTable 에 있는 데이터에 접근하는 방법이었습니다.


코드 부분은 제가 따로 테스트를 하려고 시도했지만...

언리얼 엔진4의 최소 메모리 스펙이 8GB 인데... 제 컴이 그 절반 밖에 안되는 녀석이라

여기까지 도달하는 데도 수많은 시간이 걸렸습니다 흑흑 ㅠ_ㅠ


그래서 코드로 데이터 접근하는 부분인 제가 직접 해보지는 못 했구요,

관련 자료 링크만 정리 해서 남겨봅니다.




* 엑셀 데이터로 게임 플레이 구동시키기(한글) :

https://www.unrealengine.com/ko/blog/driving-gameplay-with-data-from-excel


* 데이터 주도형 게임플레이 요소(한글, 영문은 주소에서 KOR 를 INT 로 바꿔주세요) :

https://docs.unrealengine.com/latest/KOR/Gameplay/DataDriven/index.html


2개 링크 모두 비슷한 설명 수준이구요, 자세한 설명은 아닙니다.

그냥 '이러한 흐름을 거치면 .csv 파일이 import  됩니다. 하하:D' 정도?


* 제가 방금 언급했던 미처 확인하지 못한 코드에 대한 자료는 언리얼 엔진4 위키에 있습니다. 아래 링크 참조.

https://wiki.unrealengine.com/Using_excel_to_store_gameplay_data_-_DataTables



되는 것만으로도 감지덕지한 기분으로 하다보니 미처 '이 부분은 왜 이렇게 되는거임?' 이라는 궁금증이

있었음에도 불구하고, 일단 되게끔 만드는 데 집중하다보니 부족한 부분이 많이 있습니다 ㅠ_ㅠ


혹시 지적해주실 내용이 있으시다면 조금 귀찮으시더라도

방명록에 꼭 남겨주세요. 수정해야할 부분은 수정하도록 하겠습니다 :-)



'Programming' 카테고리의 다른 글

유니티로 개발할 때 많이 쓰이는 .gitignore  (0) 2017.08.07
[C]printf()에서 "%ul"와 "%lu"의 차이?  (0) 2015.07.05
자료구조 : Linked List  (0) 2014.04.25
Delegate (대리자)  (1) 2013.12.20
[Python, C#]Lambda Form  (0) 2013.12.19
by kelicia 2014. 9. 22. 14:39