내일배움캠프 116일차 - 최종프로젝트 6일차: RTS 장르에서 건물을 짓는 법

RTS 장르에서 건물을 짓는 법

개요

나는 이번 주말에 직접 조종할 수 있는 지휘관 캐릭터를 생성해 건설/스킬사용 명령을 내릴 수 있게 만드는 역할을 부여 받았다. 특이하게도, 우리가 진행하는 RTS 팀프로젝트에서는 '지휘관'이라는 유닛이 직접 건설을 주도할 수 있는데, 지휘관이 직접 건물을 짓는다기 보다는 스타크래프트의 프로브처럼 가까이 접근해 건설 부지를 확보하면 이후에는 자동으로 건설되는 방식이다.

스타크래프트1의 프로브가 건물을 짓는 방식. 영역을 확보하면 자동으로 건설된다.

RTS 장르의 꽃인 건물 건설이 최우선이기에, 지휘관에게 이동능력을 부여하는 대로 건설기능을 먼저 추가하기로 했다. 그렇다면 건물을 건설하기 위해서는 지휘관은 어떻게 행동해야 할까?

여기서부터는 보편적인 RTS장르에 대입해서 건설기능을 가진 지휘관을 '일꾼'으로 치환해서 설명하기로 한다.

일꾼과 유닛의 이동

일반적인 RTS장르에서는 '유닛'이라는 캐릭터에게 명령을 내려 행동을 취하게 할 수 있다. 가장 일반적인 이동의 작동 방식에 대해 알아보도록 하자.업로드 중: 총 6557바이트 중 6557바이트가 업로드되었습니다.

이동좌표와 유닛

RTS장르는 거의 대부분이 캐릭터를 직접적으로 조작해 이동하는 것이 아닌 "명령"을 내려 이동을 유도한다. 그렇기 때문에 이동 시 델타시간 단위로 이동값을 계산해 움직이는 것이 아닌 목적지를 지정해 AI컨트롤러에게 좌표를 전송, 이동을 지시한다.

때문에 이동을 하기 위해 필요한 매개변수는 목적지가 되는 벡터좌표값이 될 것이다.

이동조작 시 EnhancedInput을 통해 실행되는 함수

목적지를 구하기 위해서는 커서와 맞닿는 지형의 좌표를 구해야 하는데, 엔진에서는 이미 이와 관련된 함수가 마련되어 있다. GetHitResultUnderCursor함수는 커서를 기준으로 카메라 정면을 향해 RayCast하므로(이때, 캐스팅 방향은 현재 카메라의 Projection 방식을 따른다) 함수의 Result 좌표값을 가져와 준비된 이동지시 함수를 실행하면 된다.

이동 지시 함수의 일부

인공지능(AIController)에 의해 제어받는 캐릭터는 네비메쉬 내에서만 정교한 이동이 가능하므로, 네비메쉬와 가장 가까운 좌표를 가져와(ProjectPointToNavigation) 이동을 지시(MoveTo)하게 된다. 이때 필요한 이동조건들을 임의로 설정해 전달해주면 된다.

일꾼의 건설위치 선점

테스트를 위해 임시로 지정한 '일꾼'이 만들 건물

여기까지는 유닛들의 공통적인 이동방법을 구현한 것이다. 이제는 일꾼이 '건설'을 하기 위해 어떻게 움직여야 하는지 정해야 할 때다.

스타크래프트의 건설방식

스타크래프트의 경우에는 일꾼이 건물을 지을때는 건설좌표 중심까지 이동해 건설을 시작할 수있다. 하지만 언리얼 엔진에서는 건물과 겹치기 때문에 물리오류가 발생할 가능성이 있으므로 건물과 겹치지 않는 위치까지 이동 후 건물을 건설할 예정이다.

우선, 일꾼이 지을 건물을 임의로 정하고 지정 건물의 메시에 맞게 크기를 계산하고, 이를 토대로 건설을 위해 일꾼이 이동할 위치를 선점해보자.

건물의 메시 바운드를 GetBounds()를 가져와 박스를 그려보면 위 사진처럼 건물의 크기를 반영하게 된다. 여기서 일꾼이 건설을 하기 위해 건물과 겹치지 않으면서 건물과 가장 가까운 곳으로 이동을 하기 위한 방법의 수는 다음과 같다.

1) 캐릭터가 건설구역 밖에 있다. // FBox.Intersect(CharacterBox) == false

이 경우 간단하다. 캐릭터를 건설구역의 중심으로 이동하면서 건설구역과 인접한 곳에서 이동을 멈추고 건설을 시작하면 된다.

다만, 이동 중 캐릭터와 건설경계 간의 거리를 계산하기 위해서는 건물의 Bound를 FBox로 치환해줄 필요가 있다.

FBox로 변환된 바운드는 GetClosetPointTo()라는 함수를 사용할 수 있는데, 이 함수는 임의좌표로부터 경계에 가장 가깝게 맞닿아있는 좌표를 반환해준다. 캐릭터의 현재좌표와 반환된 좌표의 거리를 계산해 일정 거리 내에 있으면 '건설할 수 있다'고 판단하는 것이다.

하지만 바로 사용하기에는 무리가 있는데, FBox는 AABB(Axis-Aligned Bounding Box) 충돌형식을 채용하고 있으므로 만약 건물이 회전값이 존재한다면 실제 건설가능 좌표를 반환할 가능성은 낮다.

이에 대한 해결법은 뒤에서 설명하도록 한다.

2) 캐릭터가 건설구역 안에 있다. // FBox.IsInsideOrOn(CharacterPos) == true

※ FBox.IsInsideOrOn() 사용 시 캐릭터의 실제좌표가 건물경계보다 밑에 있을 수 있으므로 캐릭터 Z값을 조금 더해서 검사하는 것이 좋다.

캐릭터가 건설구역 내에 있을 경우, 건설 시 건물과 겹칠 우려가 있으므로 경계 밖과 가장 가까운 방향으로 이동을 하면서, 겹치지 않으면서 인접한 곳에 도달 시 건설을 시작하면 된다.

이 경우 FBox의 GetClosetPointTo()를 사용할 수는 없다. 이미 FBox에 인접해 있다고 판단해 내부 좌표 그대로 반환하기 때문이다.

박스의 로컬좌표












댓글

이 블로그의 인기 게시물

내일배움캠프 사전캠프 - 사전캠프설 연휴 커피 파밍 이벤트 작품 [ EXTREMITY ]

내일배움캠프 29일차 - 커리어데이 2일차 : 클라이언트 프로그래머로서 포트폴리오, 입사준비팁