멀티 액션 로그라이크 게임
'로그라이크' 장르의 특성을 티베트 불교의 '윤회'라는 교리에 비유하여 제작한 게임입니다. 로그라이크 시초인 '로그'와 티벳 불교의 교리인 '윤회(육도윤회도)'를 결합한 컨셉으로 개발되었습니다.
총 22명의 팀원이 8개월 동안 협업하였고, Unreal Engine 5를 사용하여 제작했습니다. 저는 이 프로젝트에서 클라이언트 프로그래머를 맡았습니다.
또한, 파트장을 맡게 되어 관련된 기여도 같이 진행했습니다.
개발 종료 후 청강 CGC 행사(네오위즈 판교 타워)에서 전시와 함께 마무리되었습니다.
본격적인 프로젝트를 시작하기 전, 개발 환경을 구축했습니다. LFS 용량을 고려하여 저장소를 선택했습니다.
| 저장소 | Github | GitLab | Azure Devops |
|---|---|---|---|
| 제한 용량 | 1GB | 10GB | 무제한 |
현 프로젝트에서는 Azure Devops 저장소를 사용했습니다.
언리얼 엔진의 레벨 에셋(.umap)은 Google Drive로 관리했습니다. .umap 파일들은 크기가 커서 Git의 Pull, Push 작업을 느리게 만들었고, 저장소 최대 용량도 빨리 소모되게 하는 주 원인이었습니다. 이 문제를 해결하기 위해 맵 파일은 구글 드라이브로 공유하는 것으로 결정했습니다.
프로젝트 버전관리의 측면에서 신경 쓴 것은 아래와 같습니다:
주요 기능을 구현한 내용들을 정리한 로드맵입니다. 시행착오를 겪으며 점진적으로 개선했습니다.
초기에는 각 스킬을 컴포넌트로 분리해 캐릭터에게 붙이는 구조로 시작했습니다.
문제점:
• 스킬의 개수가 많아질수록 캐릭터 클래스가 복잡해짐
• 관리해야 하는 데이터와 기능이 많아짐
• 타 파트들과 같은 캐릭터 블루프린트를 수정하기 어려웠음
• 협업 시 Git 충돌 문제가 잦게 발생함
위의 문제를 해결하기 위해, 구조를 다시 변경하게 되었습니다.
Unreal Engine의 Game Ability System을 참고하여 Action System 기반의 구조로 캐릭터 시스템을 변경했습니다.
Action System 구성:
Action들은 캐릭터가 수행하는 하나의 스킬을 담당하며, 초기화 → 실행 → 중지 순으로 진행됩니다.
Action이 시작될 때, Action은 자신이 실행 가능한지를 판단합니다. 판단하기 위하여 ActionComponent가 가진 ActiveGamePlayTags Container에 Blocked Tag의 여부를 체크합니다.
Blocked Tag가 없을 경우:
1. Action의 StartAction 함수를 호출
2. ActiveGamePlayTags Container에 GrantsTag를 추가
3. Action 기능 수행
Blocked Tag가 있을 경우: Action이 실행되지 않음
• Action 클래스의 함수만 구현하면 스킬들을 만들 수 있음 (Initialize, StartAction, StopAction)
• ActionComponent로 Action들을 쉽게 관리할 수 있음
• 캐릭터의 동작 단위가 Action으로 구분되어 직관적이며, 디버깅이 편리함
C++의 Action 클래스들을 언리얼 에디터에서 각각의 Blueprint로 생성해서 관리했습니다.
직접 코드를 수정하지 않고도, 프로퍼티들을 에디터에서 쉽게 수정할 수 있게 되었습니다
협업의 측면에서:
Blueprint 안의 프로퍼티 값 변경 및 사용 방법을 공유해 기획자들과의 협업도 원활하게 진행했습니다.
근접 전투 캐릭터인 "파드마"의 Action들은 공통적인 데이터와 동작이 많았습니다.
따라서 Action 클래스를 상속받아 확장했습니다.
위와 같은 필요한 속성들을 가지고,
기능을 수행하는 AttackAction을 구현했습니다.
하지만 AttackAction이 기능을 수행하기 위한 데이터들이 많았고,
Action 클래스 블루프린트의 개수가 많아서 하나하나 클릭해 수정하는 것이 번거로웠습니다.
이를 해결하기 위해 Google Sheets를 사용했습니다.
AttackAction에서 필요한 데이터들을 모두 시트로 분리 후 틀을 만들어 기획자들에게 공유했습니다. (AttackProperties 시트, HitFrame 시트, 차징 공격 시트 등)
• 기획자가 쉽게 원하는 데이터 추가 및 수정 가능
• 시트 수정 후 플레이만 하면 되므로 테스트 속도 향상
• 기획자들이 엔진을 사용하면서 생기는 실수가 줄어듦
공통적인 데이터들 이외에 고유의 데이터가 많은 AttackAction 들은 따로 시트를 추가해서 데이터를 파싱했습니다.
Google Sheets의 시트들은 download_csv.exe를 실행하면 .csv 파일로 다운받아 Contents 폴더에 저장됩니다. 매번 파일 탐색기를 열어 더블 클릭해 실행시켜야 하는 것이 불편했습니다.
따라서 에디터를 확장해 버튼을 누르면 실행 파일이 실행되도록 구현했습니다. Editor Module을 구현해 툴바 버튼을 만들었고, 버튼을 눌렀을 때 download_csv.exe를 실행합니다.
• 엔진 내에서 편하게 csv 파일을 다운로드 가능
• 기획자, 프로그래머 모두 불편함을 해소
• 생산성이 더 올라가는 효과
Editor 를 확장하는 데 필요한 요소
1. Editor Module
2. Commands
3. Editor Style
Editor 확장 플로우
1. Editor Module Startup 시, Commands 와 StyleSet 을 등록.
2. 툴 바를 생성.
3. 생성 시 Command 와 Style 을 버튼에 맵핑
AttackAction 은 로직 뿐만 아니라 Google Sheets 에서 관리되는 모든 데이터들을 파싱 하며, 저장하고 있었습니다.
시간이 지날 수록 AttackAction 이 가진 데이터과 수행하는 기능이 많아졌습니다.
단일 책임 원칙에서 어긋날 뿐만 아니라 코드도 복잡해 진다고 판단했습니다.
따라서 AttackAction 의 데이터들과 파싱 기능을 분리해 AttackActionData 클래스로 구현했습니다.
AttackActionData 의 구조
1. Resource 와 Attack Properties, Frame 데이터
2. csv 파일을 파싱해 데이터들을 초기화하는 기능
AttackActionData 를 상속받아
공통 데이터들과 고유의 데이터들도 관리할 수 있습니다
또한 ParseOwnData 기능을 통해 고유의 데이터는 따로 파싱하도록 설계했습니다.
이제 게임 시작 시 AttackAction 을 초기화할 때,
AttackActionData 를 같이 초기화합니다.
AttackActionData 는 UDataAsset 클래스를 상속받아
언리얼 기능 중 하나인 DataAsset 형식으로 에디터로 에셋을 열 수 있도록 구현했습니다.
그 이유는 디버깅 편의성입니다
에디터에서 직접 에셋을 클릭해, 파싱했을 때 데이터가
정상적으로 들어왔는지 확인할 수 있습니다.
또한, Read-Only 데이터로 설정해 실수를 방지하게 했습니다.