본문 바로가기

팀 프로젝트(과제)

팀 프로젝트(언리얼엔진 5 기반 슈터 게임 프로젝트)

장르 : 3D 뱀파이어 서바이벌류 게임

개발 목적 : 언리얼, C++ 개발 및 팀 협업 과제 수행

개발 기간 : 25년 10월 20일 ~ 25년 11월 10일(약 3주)

 

팀 프로젝트를 3주간 진행했다.

우리 팀은 메가봉크라는 게임을 모작하여 게임을 만들었는데 메가봉크에 비해서는 많이 부족하지만 시작과 끝이 있는 하나의 완성도 있는 게임을 만들었다.

 

3주 동안 하루에 열 몇시간씩 팀 프로젝트를 만들며 많은 일이 있었지만 기록을 해놓지 않아서 대략 기억나는 부분만 적으려 한다.

다음부터는 작업을 하며 메모장에라도 적어놓을 예정이다.

 

팀에서 내가 맡은 파트는 UI와 배틀시스템을 만드는 부분이였는데 각 상황에 맞는 많은 UI(게임시작, 엔딩, HUD 등)들을 제작하고 실제 데이터와 연결하는 작업들을 했다.

게임 시작 화면


UI

각 위젯이 화면에 띄워질 때 마우스 커서 표시 여부와 게임 일시정지 같은 것을 알맞게 구현했다.

 

보스가 등장할 때 보스의 체력이 화면에 뜨고 죽으면 사라지도록 구현했다.

빨간 네모 안에 있는게 보스다

레벨업과 상점에서 각 등급 별로 버튼의 색이 달라지도록 구현했다.

노멀 - 흰색, 고급 - 파란색, 희귀 - 노란색, 전설 - 갈색

레벨업과 상점 UI

레벨 업을 할 때 현재 스탯이 어떻게 되는 지 보이도록 구현했다.

상점이 캐릭터 주위에 처음엔 20초 후에 등장하고 상점이 사라진 후 20초 후에 등장하는데 어디서 등장하는지를 알 수가 없어서 미니맵을 추가하여 쉽게 위치를 알 수 있도록 구현했다.

위젯에 다른분들이 구현해놓은 함수를 바인드 하면서 리턴 값으로 뭔가 필요를 하면 담당 하시는 팀원분에게 요청을 드려서 작업을 했다.

예시 1) 경험치 관련 변수가 Int로 되어있었는데 경험치 바(프로그레스 바)를 구현하다 보니 퍼센트로 게이지를 오르게 하는데 인트다 보니 0과 1 사이의 수를 표현할 수 없어서 경험치바가 0 ~ 0.999는 비워있고 1이 넘으면 한번에 꽉 차는 문제가 발생했다.

그래서 PlayerState 담당 팀원분께 float로 변경 요청을 드려서 해결을 했다.

경험치 바

예시 2) 상점에서 무기와 등급과 증가하는 스탯량 같은 것들을 위젯에 텍스트로 표현을 해야하는데 함수에 리턴값 중 뽑아서 쓸 수 없도록 되어있는 것들이 있어서 Shop 담당 팀원분께 요청을 드려서 수정을 하신 후 리턴 값을 뽑아서 텍스트로 표현을 했다.

상점UI의 텍스트

현재 소유중인 무기들만 화면 왼쪽 위의 칸에 아이콘이 띄워지도록 구현했다.

상점NPC에게 가까이 다가가면 E를 누르라는 위젯이 뜨도록 구현했다.

승리조건인 보스 몬스터를 처치했을 시 엔딩이 나오고 레벨과 처치한 몬스터 수, 게임 플레이 타임이 뜬다.

캐릭터 사망 시 게임오버 UI가 뜬다.

미적감각이 없어서 UI를 꾸미지 않고 기본적인 위젯들을 대략적인 위치, 크기, 필요한 텍스트들 같은거만 배치하고 바인딩 해놨는데 팀장님이 밤을 새며 꾸며주셔서 게임다운 UI가 됐다.

BATTLE

배틀 시스템은 총 6개의 무기 중 인벤토리에 4개의 무기를 담을 수 있었는데 그 4개의 무기 중 최대 사거리를 Sphere Collision의 범위를 조정해서 Sphere Collision 범위에 들어온 몬스터를 TSet에 Add하고 나간 몬스터를 Remove해서 감지 대상을 관리 했다.

Set에 담긴 몬스터들을 배열로 바꿔서 ForEachLoop로 몬스터들이 무기의 사거리 안에 들어오면 트레이스를 쏴서 감지된게 적인지, 장애물인지, 죽은 상태의 적이 아닌지 판단을 하고 만약 모든 조건이 맞다면 제일 가까운 적을 BestTarget 변수에 담아서 그 적을 향해 공격을 하는 로직을 구현했다.

TSet(Deteced Monsters)를 배열로 바꾸고 ForEachLoop로 몬스터 하나씩 순회.
무기의 사거리 안에 있는 몬스터에게 트레이스를 쏘는 로직
ReturnValue가 있거나 감지된 액터가 몬스터이고, 몬스터의 현재 상태가 Dead가 아니면 True를 실행하는 로직
제일 가까운 적을 BestTarget에 담는 로직

무기 아이템은 핸드건, 어썰트 라이플, 샷건, 스나이퍼 라이플, 수류탄, 화염병 으로 총 6가지 였다.

 

핸드건과 어썰트 라이플은 모두 한마리씩 공격을 하여 같은 로직이지만 데미지와 공격속도를 다르게 하여 차별점을 줬다.

 

샷건은 범위 안의 적들을 모두 공격하는 총이므로 샷건의 총구에 원뿔 스태틱 메시를 달아서 제일 가까운 몬스터를 향하도록 Yaw값을 회전한 다음 원뿔과 겹친 몬스터들을 모두 공격하려 했으나 총이 캐릭터의 머리 위에 있어서 총구에서 몬스터를 쏠 경우 몬스터가 캐릭터에게 근접해 있을 때 원뿔이 바닥을 향해서 공격을 하는 문제가 있어서 이펙트는 총구에서 나가지만 실제 공격 범위는 캐릭터 기준으로 원뿔 범위가 공격이 되도록 구현했다.

원뿔은 가까운 몬스터를 향해서 회전을 하도록 했지만 테스트 단계에서는 맵이 평지여서 Pitch값을 고정 시켜서 공격을 하도록 했다. 하지만 실제 플레이 할 맵에는 높낮이가 있어서 계단 위에서 몬스터를 공격할 때 Pitch값이 고정이라 계단 아래의 몬스터를 공격하지 못했다. 그래서 Pitch값도 가까운 적 기준으로 회전하도록 수정을 했다.

 

스나이퍼 라이플은 일직선상의 적들을 관통해서 모두 공격하는 총으로 샷건과 비슷한 로직이지만 긴 원기둥 스태틱 메시를 달아서 제일 가까운 몬스터를 향하도록 Yaw값을 회전하여 겹쳐진 몬스터들을 모두 공격하도록 했다. 스나이퍼 또한 총구에 달려고 했으나 몬스터가 근접하면 원기둥이 바닥을 향하게 되어 사실상 한마리만 공격하는 총이 됐다. 그래서 샷건처럼 캐릭터 기준으로 가까운 적에게 회전하도록 하고 스나이퍼도 계단 밑의 적을 공격하도록 Pitch값도 회전을 시켰다.

하지만 Pitch값을 고정하지 않고 회전을 하다보니 샷건때는 원뿔의 범위가 넓어서 괜찮았는데 스나이퍼는 원기둥이 얇아서 아주 가까운 적(캐릭터에 거의 닿은 적)을 공격하면 관통하여 일직선으로 공격하지 않고 앞의 몇마리만 공격하고 뒤의 몬스터를 때리지 않는 문제가 발생해서 그냥 Pitch값을 고정으로 해서 계단 밑의 적은 공격하지 못하게 됐다.

샷건과 스나이퍼의 범위인 원뿔과 원기둥을 BestTarget을 향해 회전시키는 로직

수류탄과 화염병은 몬스터를 담당하시는 팀장님이 시간이 남으셔서 캐릭터에서 스폰만 하면 알아서 공격이 되도록 구현을 해주셔서 스폰을 한 뒤 가까운 적에게 던지도록 하고 공격속도과 공격력 강화가 되면 변경이 되도록 구현을 했다.

BestTarget을 향해 수류탄과 화염병을 던지도록 스폰하는 로직

무기마다 총구에 Muzzle 소켓을 추가해서 총구에서 총 발사 이펙트가 나가도록 했고 총마다 다른 색의 총알이 나가는 듯한 이펙트를 추가했다. 핸드건 - 빨간색, 어썰트 라이플 - 파란색, 샷건 - 하얀색, 스나이퍼 라이플 - 노란색


트러블 슈팅

총을 쏘는 함수를 하나 구현해놓고 타이머로 함수를 일정 주기마다 호출하도록 했는데 공격 속도를 강화하려다 보니 타이머를 Clear하고 더 적은 주기로 Set을 했어야 했는데 초반에 구현할 때는 이 사실을 모르고 타이머를 총 8군데에서 사용을 해서 관리의 어려움이 있었다.

 

그래서 타이머를 최대한 줄이기 위해 타이머를 사용하는 로직을 함수화 해서 인벤토리의 슬롯별로 하나씩 타이머를 사용하도록 해서 총 4개의 타이머로 줄였다.

 

줄이고보니 또 다른 문제가 있었는데 타이머를 이용해서 이벤트를 호출해서 함수를 호출하는 방식이였는데 함수에 4가지 인자를 연결했어야 했다. 하지만 하나의 타이머가 호출하는 이벤트는 하나고 내가 함수를 호출할 곳은 두곳이였는데 인자를 하나의 이벤트에서 연결을 해버리니 다른 한곳에서 함수를 호출할 때는 인자를 연결하려 하니 연결이 안됐었다.

 

그래서 구조체를 하나 만들고 인자로 넣어야 하는 자료형으로 변수를 선언했다.

이 구조체를 타이머를 클리어하고 다시 Set하는 함수에서 변수에 알맞은 값을 넣고 이벤트에서 호출하는 함수에 이 변수들을 연결하니 문제가 해결이 됐다.


회고

처음에는 UI만 담당했지만 중간에 BATTLE을 맡게 되어 어떻게 해야할지 막막해서 뭐라도 해보자 하고 캐릭터 블루프린트에서 구현을 시작해서 끝까지 블루프린트로만 구현을 하게 됐는데 다음에는 C++을 사용해서 구현을 해보고 싶다.

 

처음 기획 단계에서 많은 기능을 추가해보자고 시작을 했었는데 시간이 부족해서 기본적인 기능들만 구현하고 더 다양한 기능들을 구현해보지 못한 점이 아쉽다.

 

팀장님이 STOVE에 게임을 올린다고 하셨는데 올리게되면 글에 다운로드 링크를 추가할 예정이다.