들어가며
이번에 한국 공학 대학교에서 주최하는 2024 한국 공학 대전에 참가했다.
한국 공학 대전은 지난 8월 말 학교 측으로부터 제안받아 알게 됐는데, 반쯤은 필참인 행사여서 9월 25일부터 26일까지 양일 간 졸업 작품, <Breath in Winter>(이하 졸작)를 전시했다.
졸작 전시를 준비하는 과정에서 삽질을 하며 프로젝트를 개선하기도 했고, 전시 중 느낀 것들도 많아, 이번 기회에 한국 공학 대전을 준비하고 참여한 후기에 대해서 적어보려고 한다.
글은 총 2편으로 구성돼있으며 목차는 아래와 같이 구성할 예정이다.
목차
상편 : 프로젝트 준비 과정
- 무엇을 준비하고자 했는가?
- 개선 : 히트 박스 (Hit Box)
- 개선 : 레벨 업 & 업그레이드
- 결과
하편 : 프로젝트 전시 과정
- 전시 준비
- 시상식
- 전시
- 느낀 점 (후기)
- 결과
그럼 긴말 말고 같이 한번 확인해보도록 하자.
프로젝트 준비 과정
무엇을 준비하고자 했는가?
나는 지난 2024 공학 대학 캡스톤 디자인 페어에서 졸업 작품을 전시했다.
2024 공학 대학 캡스톤 디자인 페어 후기
들어가며 지난 6월 5일 수요일, 교내 공학 대학 캡스톤 디자인 페어에 참가했다. 앞서 캡스톤 디자인 결과 발표회를 마치고 휴식을 취하고 있는 도중 참가작으로 선정됐다는 연락을 받았는
memoria-aeon.tistory.com
당시에는 단순하게 전차를 타고 적을 처치하는 걸 코어 메카닉으로 삼아 구현한 뒤, 나이아가라 시스템을 활용한 반응형 총탄 시스템과 추후 업그레이드 기능을 넣을 수 있게 몇 가지 기반을 마련한 상태로 프로젝트를 마무리 지었다. 이렇게 만든 결과물을 아래와 같았다.
분에 넘치게 대상을 수상했지만, 당시 수준으로는 출시까지는 어렵겠다는 생각을 했고, 이에 성장을 명목으로 생각의 뒤편에 묻어둔 채 시간만 흘러갔다. 그러던 와중 위에서 언급한 것처럼 학교 측으로부터 한국 공학 대전에서 졸작을 전시할 것을 제안받았다.
당시에 졸업 요건으로 인해 창업 대체 학점 인정제에 신청하지 못해서 사실상 <Breath in Winter>는 추가 개발이 어려운 상황이었는데, 마침 계속 미뤄두기 찜찜해서 참여 의사를 밝히고 개선을 시작했다.
<Breath in Winter>의 개선을 결정하고 가장 먼저 한 일은 패키징이었다. 지난 전시에서 담당 조교님께 노트북을 대여받을 수 있었지만, 이번에는 타지에 혼자 가서 작품을 전시해야 했기에 뚜벅이인 나로서는 패키징 외의 방법이 없어 보였다.
그래서 어렵지만 'Oculus Quest 2'(이하 퀘스트2)로 작품을 빌드하고자 했고, 이것저것 시도하다가 커뮤니티 글의 도움을 받아 성공적으로 패키징 할 수 있었다.
다만, 이렇게 패키징 한 결과, 퀘스트2에서 정상적으로 구동되지 않았다. 아래는 기본 VR 템플릿 맵과 졸작 프로젝트를 패키징한 빌드를 각각 실행해 본 결과인데 기본 VR 템플릿 맵은 잘 구동되는 반면, 졸작 프로젝트는 구동 즉시 종료되는 걸 확인할 수 있었다.
동일한 설정으로 빌드했는데 졸작 프로젝트에만 문제가 생겼다는 건 최적화 문제로밖에 보이지 않았다. 그래서, 아래의 2가지를 고려해 봤다.
- 프로젝트를 정리할 겸, 기본 맵에 필요한 에셋과 코드를 기능 단위로 최적화하면서 옮긴다.
- 깔끔하게 퀘스트2 패키징을 포기한다.
다들 예상하듯이 내가 선택한 건 패키징을 포기하는 것이었다. 처음에는 리팩토링과 최적화까지 한 번에 해보겠다고 UML 구조도를 그려가면서 이것저것 해봤는데 결과는 패키징을 합쳐 2주 정도의 시간이 허비됐을 뿐이었다.
사실상 리팩토링과 최적화를 성공해 퀘스트2로 이식한다고 해도, 퀘스트2라는 기기가 갖는 한계는 분명하기에 내가 만족할만한 퍼포먼스를 낼 수는 없었을 것이다. 나는 이 점을 간과하고 근거 없는 자기 과신으로 인해 2주라는 시간을 잃어버렸다.
결국 원점으로 돌아와서 남은 2주간 프로젝트 개선을 위해 할 수 있는 것들에 대해서 고민을 해봤다. 개선 시 효과적이면서도 2주 안에 해결할 수 있는 문제들을 정리하면 아래와 같았다.
- 히트 박스(Hit Box)가 정상적이지 않다.
- 기껏 만들어둔 나이아가라 반응형 총탄 시스템이 활용되지 않는다.
이러한 관점에서 이 2가지를 해결하게 됐는데, 그 과정은 이후 항목에서 함께 살펴보도록 하자. 그럼 이쯤에서 내용을 정리하고 이번 항목을 닫겠다.
정리
1. 프로젝트를 퀘스트 2로 패키징 하려고 했으나 최적화 문제로 구동에 실패했다.
2. 리팩토링과 최적화를 시도했으나 전시를 준비하는 과정에서 해야 할 작업이 아니라고 생각해 중단했다.
3. 노트북을 대여해 PC-VR 플레이 형태를 유지하기로 하고, 그 대신 남은 2주간 개선할 수 있는 부분에 대해 고민해 봤다.
개선 : 히트 박스 (Hit Box)
졸업 작품 제작 당시의 나는 나이아가라의 각 모듈을 활용해서 다양한 총탄을 만들어보고 싶었다. 이에 성능은 무시하고, 나이아가라의 충돌 모듈을 통해 블루프린트로 데이터를 전달하도록 구현했다.
이 과정에서 충돌 처리 블루프린트는 총탄 파티클이 충돌했는지 여부만 알 수 있을 뿐, 무엇에 충돌했는지는 알 수 없어서 전달받은 충돌 position에서 ray trace를 통해 다시 한번 충돌을 판정하는 방식으로 구현했다. (비효율의 극치..)
이때 충돌한 actor를 찾는 경우, 충돌 position으로부터 z 축 기준 -10까지 ray trace를 통해 검출했기에, 충돌 영역에 정확하게 맞지 않으면 충돌 처리가 제대로 되지 않는 문제가 있었다. 심지어 그 몸통이라는 것도 캐릭터 모델링 collision이 아니라 기본 캐릭터 capsule collision에 맞춰야 했기에 플레이어 기준에서는 직관적이지 않기도 했고 말이다.
이에 간단하게 히트 박스를 추가해서 충돌을 확인할 수 있게 변경했다. 이 과정에서 모든 공격에 쓸 Bullet trace channel과 모든 피격 검출에 쓸 Hitbox collision channel을 추가해 아래와 같이 설정했다.
여기서 hitbox가 overlap인 이유는 충돌 위치에서 ray trace로 충돌 검출을 하는 경우, 제대로 된 검출이 불가능하기 때문이다. Hitbox collision channel은 bullet에 대해 block 되기에 충돌 위치가 히트 박스 외부로 잡힌다.
혹자는 ray trace를 x나 y축으로 뻗게 하면 되지 않냐고 할 수도 있는데, 그럼 몬스터 진행 방향에 따라 충돌 검출이 될 수도, 안 될수도 있어서 그 방법은 사용하기 어려웠다. 그래서 그냥 단순하게 충돌 위치에서 hitbox collision channel로 sphere collsion을 만들어 overlap 되는 히트 박스를 검출하도록 구현했다. 이 때문에 hitbox를 overlap으로 설정한 것이다.
개선 결과는 아래와 같다.
결과는 잘 나왔는데.. 만약 나중에 추가 개발을 한다고 하면 성능 분석해 보고 나이아가라 시스템과 블루프린트 연동을 삭제할 것 같다. (충돌 처리 과정이 복잡해서 성능이 좋지 않을 것 같은 느낌.)
구조가 복잡해서 그냥 정석대로 총탄 BP 하나를 만들어서 나이아가라 시스템이랑 콜리전 영역을 부착하는 방식으로 처리하는 게 가장 속 편할 것 같다는 생각을 했다.
나이아가라 모듈과 같은 기능이 필요하면 구현하면 되고 말이다.. 아무튼 이번 항목을 정리하면 아래와 같다.
정리
1. 총탄 충돌 처리는 나이아가라 시스템과 블루프린트를 연동해서 구현했다.
2. 기존에는 캐릭터 capsule collision 영역을 정확하게 맞춰야 피격됐다.
3. 캐릭터 피격 처리는 큰 히트 박스를 추가해서 해결했다.
4. 추후에 개발을 한다면 성능 확인 후 충돌 처리 방식을 바꿀 것 같다.
개선 : 레벨 업 & 업그레이드
다음으로는 이전에 만들어 둔 나이아가라 반응형 총탄 시스템을 활용해 재미를 만들기 위해 업그레이드 기능을 구현하기로 했다.
<Breath in Winter> - User parameter에 반응하는 Niagara VFX
소개 앞서 수확제 글에서 언급한 것처럼 올해 초부터 개인 졸업 작품으로 VR FPS 게임을 개발하고 있다. 장르를 굳이 정리하자면 스팀 펑크 배경, 디펜스 슬래셔 게임이라고 할 수 있을 것 같은데,
memoria-aeon.tistory.com
업그레이드 기능은 단순하게 <Vampire Survivors>처럼 적을 처치하면 경험치를 얻고, 경험치를 쌓아 레벨 업을 하면 보상을 제시받으며, 그중 하나를 선택해 무기나 전차를 강화할 수 있게 구성하고자 했다.
이전에 반응형 총탄 시스템을 구성하면서 무기 스탯을 정의해 놓고 나이아가라 시스템과 연동해 놨으니, 업그레이드 구현을 위해 남은 건 아래와 같았다.
- 경험치 시스템 추가 및 UI 제작
- 보상 목록 정리 후 랜덤 보상 선별 메서드 구현
- 레벨 업 시 게임 진행을 제어(일시정지/재개)하고, 선별된 보상을 UI에 띄우는 기능 구현
가장 먼저 경험치 시스템과 UI 같은 경우는 아래와 같이 간단하게 구현할 수 있었다.
플레이어 경험치의 경우는 간단하게 속성만 정의해 두고, 다른 속성과 마찬가지로 계산 메서드를 추가해 놨다.
경험치 계산 메서드에서는 현재 경험치가 최대 경험치 이상으로 커진 경우, 이전에 만든 SetWidgetComponentVisibility 메서드로 Rewards UI를 찾아 visible 하게 바꾸고, 게임을 일시 정지하도록 구현했다. (UI 비활성화와 게임 재개, 경험치 차감은 보상 선택 시 호출되는 메서드에서 처리하도록 구현했다.)
그 뒤, 몬스터 사망 이벤트에서 플레이어의 현재 경험치를 증가시키게 만들고, HUD와 연동해 주는 방법으로 구현할 수 있었다.
기획 관련 TMI이지만, <Breath in Winter>에서는 파워가 곧 속도이며 감당할 수 있는 최대 과부하도가 되도록 구현했다.
보상을 통해 파워를 늘릴 수 있고, 피격을 받으면 파워가 감소되도록 구현하였으며, 이후에는 현재 파워 값에 따라 등장하는 몬스터의 유형과 수를 제어하도록 구현하고자 했다.
이를 통해, 유저의 실력에 비해 난이도가 쉬우면 파워가 높아져 더 어려운 적과 빠르고 화려하게 전투를 하도록, 난이도가 어려우면 피격 후 자연스레 속도가 감소되어 단조로운 패턴의 적들과 전투를 하도록 유도하고자 했다.
이런 방법을 통해 유저가 자신의 실력에 상관없이 플레이할수록 점차 몰입할 수 있도록 만들고자 했다. (구현은 안 됐지만.. 😅)
다음은 보상인데 가장 먼저 어떤 것을 보상으로 제시할지, 그리고 보상은 어떻게 구현할지 고민해 봤다. 우선 업그레이드 시스템의 목적이 나이아가라 반응형 총탄 이펙트를 활용하는 것이니, 보상은 무기와 전차의 속성을 강화하도록 구성하고자 했다.
이때 업그레이드 시스템의 묘미는 유저가 원하는 이상향을 향해 파라미터를 조정하는 것에 있다고 생각했는데, 단순히 긍정적인 효과만으로 그 이상향에 선형적으로 다가가도록 구성하는 것이 아닌, 긍정적인 효과와 부정적인 효과를 함께 주어 이상향에 수렴하는 느낌으로 다가가도록 만들고자 했다.
하나가 오르면 다른 하나를 조정해야 하고, 다른 하나를 조정하면 또 다른 하나를 조정하면서, 레벨 업이라는 이벤트의 반복을 통해 본인이 원하는 수치로 수렴하도록 디자인하고 싶었다.
그리고, 이런 시스템의 핵심으로써 각 속성의 최댓값, 최솟값을 정의해 일정 수준 이하에서는 부정적 효과 적용이 무시되는 경우를 만들어 유저가 이를 이용하도록 만들고 싶었다.
그 과정에서 자연스럽게 컨셉이 만들어짐과 함께 유저 스스로 효율적으로 플레이하고 있다는 느낌을 받기를 원했고 말이다.
그럼 이제 '이걸 어떻게 구현하느냐'라는 질문이 남았는데, 솔직히 랜덤 보상 선별 같은 경우는 보상이 얼마 되지 않으니 하드 코딩으로 금방 구현할 수 있으나, 또다시 병이 도져서 데이터테이블을 만든 후 엑셀과 언리얼이 연동되도록 구현하고자 했다.
이에 데이터의 규격(가짓수, 유형 등)을 정의한 뒤, 보상 데이터테이블을 구성했다. 그리고, 이 과정에서 이왕 하는 거 유저 스탯과 무기 스탯도 함께 연결하자는 생각을 해서 결과적으로 아래와 같은 데이터테이블이 만들어봤다.
이후에는 CSV로 export 한 뒤, 언리얼로 import 하면 되는데 수정할 때마다 일일이 변환해 주는 게 번거로워서 GPT를 통해 VBA로 변환하는 스크립트를 작성했다.
그리고, 데이터테이블에 사용할 구조체를 선언 후, import 하여 아래와 같이 정상적으로 데이터를 읽어오는 걸 확인할 수 있었다. 추가로, 이렇게 한번 설정해 두면 CSV 파일이 바뀔 때마다 알아서 업데이트하는 걸 확인할 수 있었다.
이렇게 읽어온 데이터 테이블 에셋들은 game instance에 데이터 관리 메서드를 추가해서 어디서나 접근할 수 있도록 구현했다. 이때 유저 스탯이나 무기 스탯은 각 요소 초기화 시 읽어와 할당받도록 구현했고, 랜덤 보상 선별은 보상이 게임 초기화 시, 보상 선택 시 아래 선별 함수를 호출해 reward UI를 업데이트하도록 구현했다.
보상 스탯 적용도 이와 비슷하게, 스탯 이름과 값을 인자로 받아 스탯을 업데이트하는 메서드를 만들었고, reward UI에서는 target object 이름으로 캐스팅한 뒤 해당 메서드를 호출하여 보상을 적용하는 방식으로 구현했다.
그 결과는 아래와 같다.
한 가지 생각나는 개선할만한 부분은 엑셀에서 휴먼 에러 때문에 발생할 오류를 방지하기 위해서 조건부 서식이나 매크로로 검증하는 건데.. 사실상 여기서 완칠 것 같아서 그냥 생각만..! 😋😋
아무튼 이렇게 레벨 업과 업그레이드까지 확인해 봤다. 이번 항목의 내용을 정리하면 아래와 같다.
정리
1. 나이아가라 반응형 총탄 이펙트를 활용하기 위해 레벨 업과 업그레이드 시스템을 구현했다.
2. 데이터테이블을 만들어 유저 스탯, 무기 스탯, 보상 목록을 언리얼과 연동했다.
결과
결과적으로 아래와 같이 플레이할 수 있게 개선했다.
후기
전시 후기는 다음 편에 적기로 하고 개발 후기만 적자면, 이대로는 앞으로 개발이 힘들겠다는 생각을 했다.
가장 먼저 내 방식을 생각해 보면, 원리 하나하나를 꼼꼼하게 이해하고 구조를 깊게 고민한 뒤 구현하는 것이 아닌, 내가 원하는 기능을 위한 코드를 찾아 알맞게 변형해 덕지덕지 기워내는 형태다 보니 기술 부채가 쌓여가는 게 실시간으로 체감됐다.
그래서 리팩토링과 최적화를 해보겠다며 설쳤던 거고, 그래서 문제가 생겼을 때 무엇을 활용할 수 있는지 쉽게 찾지 못했던 거다. 리팩토링과 최적화는 어떻게 할 수 있다고 해도 그 이후 또한 문제다. 가장 기본적으로 나는 언리얼 엔진을 모른다. 엔진 동작 방식을 모르고, 컴퓨터 그래픽스에 대해 무지하다.
틈틈이 공부하며 렌더링 파이프라인이라던지, 엔진 로딩 방식, 엔진에 어떤 헤더와 메서드가 있는지 알아봤지만.. 뭔가 이것들을 엮을만한 줄기가 없는 느낌이다. 직설적으로 말하면 개발에 대한 기본기가 부족하다고 생각한다.
기본기라고 생각했던 알고리즘이라던지, 학교에서 배웠던 운영체제, 컴퓨터 네트워크와 같은 지식들은 서로 엮이지 않고 조각조각 떨어져 있다. 참조되지 않아 잊혀지고 있고 말이다.
어차피 내 진로가 기획이니만큼 크게 필요는 없으니 버려도 되기는 한데, 욕심이 많아서 또 버리기는 싫다. 그래서, 어차피 조만간 기획 포폴도 만들어야 하니 당분간 모든 개발은 접고, 기획 작업과 개발 기본기 쌓기만 해보려고 한다.
나는 잘하고 있는 건가?
'일상' 카테고리의 다른 글
근황, 나라는 기획자에 대해서 (4) | 2024.11.16 |
---|---|
2024 한국 공학 대전 후기 (feat. Breath in Winter) (하) (3) | 2024.09.30 |
<Sekiro™: Shadows Die Twice> - 적귀 CUT (0) | 2024.08.07 |
[2024 넥슨 대학생 게임잼 후기] Lib's Rarry (2) | 2024.07.29 |
2024 공학 대학 캡스톤 디자인 페어 후기 (0) | 2024.06.06 |