이건 내가 충돌 연구소장이 되기까지의 이야기다(Feat 말하는 걸 잊은 속도, 중력, 캡슐 컴포넌트, 예수(?), 리버스 슈퍼맨(?))

정윤재·2026년 8월 17일
post-thumbnail

안녕하세요! 어쩌다 보니 제가 주(소리)님의 의지를 이어 충돌 연구소장이 되었는데요. 개인 프로젝트인 알라딘 프로젝트를 진행하면서 생겼던 문제들을 소개하였습니다. 움직임 속도 이상, 폰의 회전에 맞지 않는는 유저의 화면, 배치된 엑터가 거리를 이용하지 않고 충돌시 방향이 바뀌게 만들고 싶었지만 벽을 인식하지 못 하는 문제, 캡슐 컴포넌트의 sphere component의 크기를 직접 값을 입력하여 처리할려 했지만 예수(?)가 된 문제, 중력이 아래로 적용이 되지 않고 플레이어 발 끝으로 적용 돼 회전했을 때 발끝으로 날아디는 리버스 슈퍼맨 문제입니다. 이 중에서 직접 해결한 문제들도 있고 도움 받아서 해결한 문제들도 있고 해결하지 못한 문제들이 있습니다. 일단 하나씩 천천히 살펴보겠습니다.


1. 거리가 아닌 충돌로 이동 거리 제한

엑터가 maxrange를 써서 일정 구간만큼 가면 다시 방향이 바뀌어서 오고 가는 그런식으로 장애물을 설정했었습니다. 그러다가 문득 이런 생각이 들더라고요. 전에 블프해서 장애물이 beginoverlap을 사용해서 벽이랑 부딪히면 방향을 바꾸게 하는 것을 C++로 바꿔보자는 위험한 생각이요. 예.... 일단 도전!

먼저 false로 설정했던 물리 시뮬레이션은 계속 꺼놓고 바디 콜리젼을 켜봅시다. 여기서 잠깐!! 이 두개 뭐냐?
물리 시뮬레이션은 직접 물리 법칙을 설정과 관련된 것입니다. 이 것을 키면 mesh 가 물리 엔진의 영향을 받는 물체가 됩니다.예를 들어
-중력에 떨어짐
-다른 물체와 충돌하면 밀림
-물리적인 힘을 받음
-질량, 마찰, 충격량 등의 영향을 받음
즉, 공을 물리적으로 굴리는 것과 비슷합니다.
우리는 C++ 코드로 직접 위치를 움직이고 있기 때문에 false로 계속 남겨둡시다. SetNotfyRigitBodyCollision은 이 컴포넌트가 충돌했을 때 hit 이벤트를 알려주는 설정입니다. 우리는 이것을 켜서 충돌 판정을 일으킬 겁니다.
자 그럼 켰으니 이제 이것을 위한 코드를 짜줍시다. 일단 충돌시 방향 전환이 되도록 해야겠죠?

충돌시 엑터가 플레이하는 캐릭터가 아니라면 -1을 곱해서 방향 전환을 설정해줬습니다. 캐릭터랑 충돌하면 데미지를 입히게 하고 사라지게 할려고 까지 기획은 했었는데 시간이 없어서 일단 이 정도에서 그쳤습니다. 그리고 이러한 장애물이 매 틱마다 움직여야겠죠?

현재 위치 정보를 받아서 그 위치 기준 이동 속도, 프레임, 방향을 곱해서 더한 새로운 위치를 구했습니다. 그리고 엑터의 위치를 설정하는 함수에서 충돌 발생 변수를 넣어서 움직이다가 충돌하면 방향이 -1이 곱해지니 다른 방향으로 가곘죠? 이제 한 번 실험해보러 가겠습니다.
돌이 움직이는데 어......? 왜 안 튕기지? 이상하네... 혹시 내가 함수를 발동(?)을 안 시킨건가....

아닌데 분명히 생성자에 그 기능을 넣어놨었는데? 흐음 그럼 에셋 문제인가? 에셋의 콜리젼 설정을 변경하러 가보겠습니다.


돌이랑 벽들의 collision 설정을 모두 all block으로 실험해봤습니다. 놀랍게도 그대로였습니다....에셋의 문제인가? 새로운 프로젝트를 열어 같은 코드로 실험을 해봤습니다.

어...?일단 에셋을 바꾸니 충돌 감지는 되는데 아싸리 멈춰버리는 군용...일단 제가 펩에서 가져온 에셋은 확실히 충돌 설정이 이상한 것 같은데 그것을 건들 일은 지금 제 수준에서는 잘 못 할 거 같으니 이 박스를 팅겨내게 해보도록 합시다. 다시 코드를 한 번 살펴보러 갔습니다. 일단 충돌 처리가 제대로 되는지부터 확인하겠습니다.

부딪혔을 때 로그가 나오도록 설정했습니다. 이러면 벽에 부딪히면 로그가 뜨겠죠? 실험하러 가보겠습니다.

어 음...왜 벽에 부딪혔는데 로그가 안 뜨지? HIT 쪽이 지금 이상한 거 같습니다. 이거 충돌 감지가 안 되나? 혹시 모르니 collision 설정 한 번 확인하러 가보겠습니다.

기본 default값이길래 혹시 몰라서 blockall로 하고 실행해봤습니다. 예. 안 됩니다. 확실히 이러면 제 코드가 문제일 거 같습니다. 코드를 한 번 살펴보러 가겠습니다.

....?나 왜 UFUNCTION을 주석 처리했냐....이러니까 언리얼 엔진에서 안 되지... 못 찾으니까....설마하고 찾아보니 알라딘 폴더도 저렇게 되어 있네요...일단 테스트에서 되는지 확인해보겠습니다.

!!!!!아니 이렇게 허무하게 되다니 혈압이 올라가는 동시에 기쁨을 느끼는 건 처음인 거 같습니다. 아마 제가 임시로 max range로 구성할 때 나중에 꼭 다시 돌아와서 널(?) 물리치겠다 다짐하면서 주석 처리했던 거 같은데 HOXI? 알라딘 프로젝트에서도 될지도???

그전에 정화님께서 알려주신 방법으로 토대로 콜리젼을 한번 삭제하고 auto 생성해봤습니다. 전에도 콜리전이 있었지만 혹시나 해서 한 번 초기화를 하고 auto 생성으로(아니 이걸 진작 알았다면 저 아래에서 콜리전 넣는 거 안 해도 됐잖아?라고 하면 안 되겠죵?) 넣었습니다. 또한, show를 통해서 저 콜리전이 보이시죵? 콜리전이 있는 게 확실합니다. 이제 실험하러 가봅시다.

아....ㅠㅠ 확실히 에셋 쪽에 문제가 있었나 봅니다. 아직은 제가 받은 에셋들까지 바꿀 실력이 안 되기에....아는 범위까지 해봤지만 이건 이제 제가 더 배우면 고치러 와봅시다. 그래도 일단 코드가 정상적으로 작동하니 저 에셋을 바꾸거나 수정하면 될 거 같습니다.
반쯤(?) 성공!

2. 움직임 속도 이상

폰이 움직이는데 많이 느려요. 이건 블프에서 해결 할 수 있고 매우 쉬운 문제지만 쉬어가는 타임으로 잠깐 소개하겠습니당~!


코드는 이런 형식으로 방향을 받아서 로컬 기준으로 움직이게 설정했습니다. 하지만!!

쥐발톱의 때만큼 움직입니다. 안타까운 일입니다. Speed의 Blueprint UPROPERTY()를 BLueprintReadWrite로 설정했기에 한 번 블프에서 속도를 테스트하면서 맞는 속도를 찾앚줍시다.

과감하게 한 번 가보겠습니다. 만으로 설정해보고 테스트해보았습니다.

빠름!빠름!빠름 너무 빠르네요.

다시 속도를 낮춰봅시다. 1000으로 설정해봤습니다.

아주 적당한 속도가 되었습니다. 이 속도로 설정 후 컴파일하고 저장했습니다. 앞으로 이 친구는 이게 기본 베이스 속도가 될겁니다.

그리고 모든 프레임에서 일정한 속도가 되어야하기 때문에 Deltatime을 곱해주었습니다. 하마터면 까먹을 뻔 했군용. 일단 이렇게 문제 하나는 해결했습니다.
하지만 이 친구는 우리들 중 가장 최약체! 다음 보스(?)를 만나보겠습니다.


3. 폰의 회전에 맞지 않는는 유저의 화면


먼저 마우스 값을 입력 받고 그 값이 0이 아닐 시 그 값을 프레임 값 곱해주고 카메라 스피드 값 곱해(블프에서 변경 가능)준 값을 AddActorLocalRotation의 매개변수 FRotator에 넣어서 이동하게했습니다.


또한, 이러한 움직임을 UsePawnControlRotation을 통해 폰의 SpringArmcomp(뒤에 카메라)에도 적용하게끔 설정했습니다.

홀리...저는 일단 W만을 누르고 있습니다. 일단 확실히 잘 움직이긴 합니다. 폰이 바라보는 방향으로 가는 형태는 제가 의도한 게 맞는데 화면이 맞지 않네요. 그럼 한 번 화면을 맞추러 한 번 가보겠습니다.
컨트롤러에 rotation을 넣어주거나 UsePawnControlRotation을 끄면 화면에 맞춰지지 않을까라는 생각이 들었습니다. 아무래도 저 영어를 해석해보면 pawn의 rotation을 위주로 컨트롤하는 것이 때문에 이것을 끄면 컨트롤러가 (?) 멀쩡해지지 않을까라는 실험 정신이 들었습니다. 일단 먼저 false로 꺼둡시다.

음....화면은 이제 잘 고정이 되었지만 움직임이 이상합니다. 아무래도 pawncontrolrotation을 써야 폰 로테이션 위주로 컨트롤이 되는데 그것을 껐기에 생긴 문제로 발생한 거 같습니다. 카메라는 의도대로 잘 고정이 되었지만...


이 것은 제가 의도한 것이 아니기에 다시 켜두고 컨트롤러 포인터 변수를 선언하고 컨틀롤러를 가져오고(Carpet인 이유는 원래 알라딘의 양탄자를 위해서 만든 거였는데 마감에 맞추다보니 이렇게 되었다는 매우 안타까운 이야기...) pawn이 움직이는 rotation 값도 적용을 시켜줍시다.

이게 뭐지....? 화면은 고정되는데 우리 폰이 아주 아주 이상해졌습니다. 어 흠 아무래도 이 문제는 좀 다른 사람들 코드들을 보면서 인사이트를 얻어야겠습니다.

어벤져스 어셈블!(도와주신 태우님, 우혁님, 수현님 감사합니다.)

전 일단 제 코드를 이런 식으로 짜서 움직임을 구현했었는데 다른 분들은 정상적으로 작동하고 GetForwardVector랑 GetRightVector를 쓰지 않더라고요. 엇? 필수 구현 가이드가 Forward/Right 벡터를 쓰는 거 아니였나? 생각이 들어서 다시 한번 구현 가이드를 살펴봤습니다.

찾아보니 기본적으로 AddActorLocalOffset()이 pawn의 Foward/right벡터를 기준으로 결정되더라고요. 그렇다면 따로 또 구해서 넣은 제 케이스의 경우 두번이 적용 되어서 이상하게 움직이는 게 아닐까 생각했습니다.

그래서 이렇게 방향을 빼고 FVector로만 구성해서 진행해봤습니다.

잘 작동하군요. 무빙을 요리조리 벽이랑 안 부딪혀려고 하는 모습입니다. 제일 골치가 아팠던 문제였는데 해결이 되어서 너무 다행입니다. 그리고 다시 한번 도와주시고 같이 고민해주신 분들께 감사합니다.


4.캡슐 컴포넌트의 sphere component 문제

게임을 만들다 보면 다양한 에셋들을 다루게 되는데요. 캡슐 컴포넌트를 box랑 sphere로 설정하는 거 같더라고요. 더 있을 거 같긴한데 아직까지는 뭐가 더 있는지는 잘 모르겠습니다. 예...뭐 그리고 보니까 기본 디폴트 값으로 생성시 스피어로 해주더라고요. 근데 그러다 문득 박스나 스피어 말고 다양한 형태의 캡슐이 필요할 거 같은데 한 번 직접 만들어 보는 것 같다라는 생각이 들어서 도전 해봤습니다. 도전!

먼저 헤더 파일에 가로 반지름 길이(withsize), 세로 반지름 길이 (heightsize)로 설정한 후 소스파일에서 그 값을 받아서 캡슐 사이즈이 되도록 설정해봤습니다.

그리고 그것을 블프에서 변경이 가능하도록 해서 값을 조금 바꿔보고 실험을 해봤는데 10000까지 올려도 적용이 안 되더라고요. 답답한 나머지 이것 저것 건들여보다가 문제가 하나 생겼습니다.


어 우짜다가 보니 예수가 되었는데요. 이건 사실 캡슐 컴포넌트의 shape을 잘못 건들여서 생긴 문제입니다. 아무래도 지금 제 수준에서 언리얼 에디터에서 기본적으로 주는 설정들을 사용하지는 않고 건들이는 것은 어려워 보입니다. 안타까운 일입니다. 그래서 기본적으로 주는 shape 기능으로 맞춰봤습니다.


52, 10으로 하고 메쉬를 조금 움직여서 맞춰주니 딱 맞더라고요. 일단 이렇게 해결하긴 했으나 제가 의도한 대로 된 바가 아니라 아쉽습니다. 나중에 더 공부를 해서 꼭 이 문제를 한 번 해결하고 말겠습니다.

처참히 실패!


5.리버스 슈퍼맨 문제

먼저 중력을 적용하기 위해 코드를 짰습니다.

일단 플레이어가 땅에 닿아있는지를 확인하기 위해 현재 위치에서 월드 Z축 아래 방향으로 LineTrace를 쏴줬습니다. 이때 자기 자신까지 충돌 대상으로 인식하면 안 되기 때문에 AddIgnoredActor(this)를 사용해서 자기 자신은 충돌 대상에서 제외했습니다.
이렇게 LineTrace를 통해 땅에 닿았는지 확인하고, 땅에 닿았다면 VerticalVelocity를 0으로 초기화해줍니다. 반대로 땅에 닿아있지 않다면 중력 가속도를 DeltaTime과 함께 적용해서 점점 아래로 떨어지도록 만들었습니다.
그리고 계산된 VerticalVelocity를 AddActorLocalOffset()에 넣어서 실제 플레이어의 위치를 이동시켜줬습니다. 음... 여기까지만 보면 아주 정상적으로 중력이 적용된 것 같습니다.

띠용? 발끝으로 중력이 작용이 되어서 회전을 했을 때 발끝으로 날아다닙니다. 이렇게 리버스 슈퍼맨이 탄생했습니다. 이건 pawn 위주로 중력이 적용한다고
문제는 제가 Local을 사용했다는 것입니다.
처음에는 그냥 Z축에 값을 넣었으니까 당연히 아래로 떨어지겠지!라고 생각했는데, AddActorLocalOffset()은 월드 기준이 아니라 현재 액터의 로컬 좌표를 기준으로 이동합니다. 그렇다면 플레이어가 회전하게 되면...?
예. 중력의 방향도 같이 돌아가버립니다.
그래서 플레이어가 회전하면 바닥으로 떨어지는 게 아니라 플레이어의 발끝 방향으로 날아가는 기괴한 현상이 발생하게 됩니다.

그럼 월드 좌표로 설정해보고 테스트해보겠습니다.

다행히도 잘 작동합니다! 옆으로 회전해도 움직이지 않습니다. world로 하니 pawn의 방향에 구속 받지 않기 때문에 당연한 일이지만 해결 되어서 참 다행입니다.


6. 마무리

이렇게 해서 충돌 연구소장이 되기까지의 여정이 끝났습니다.

이번 프로젝트를 진행하면서 생각보다 정말 다양한 문제를 만났는데요. 어떤 문제는 직접 해결하기도 했고, 어떤 문제는 다른 분들의 도움을 받아 해결하기도 했으며, 어떤 문제는 아직도 해결하지 못한 채로 남아있습니다.

특히 처음에는 그냥 “왜 안 되지?” 하고 코드만 계속 들여다봤는데, 하나씩 확인해보면서 코드 문제인지, 에셋 문제인지, 설정 문제인지 구분하는 과정 자체가 중요하다는 것을 많이 느꼈습니다.

물론 중간중간 UFUNCTION()을 주석 처리해놓고 왜 안 되냐고 고민하거나, Local로 중력을 적용해놓고 리버스 슈퍼맨을 만들어버리는 등 제 스스로 문제를 만들어낸 경우도 있었지만요. 예... 이것도 경험이라고 생각하겠습니다.

그리고 이번에 해결하지 못한 문제들도 언젠가는 다시 돌아와서 해결해보고 싶습니다. 지금은 제 수준에서 건드리기 어려운 부분도 있지만, 더 공부하고 나면 예전에 안 됐던 것들이 왜 안 됐는지 이해할 수 있을 것 같기 때문입니다.

결국 이번 프로젝트에서 가장 많이 배운 것은 문제가 발생했을 때 바로 포기하지 않고 하나씩 원인을 찾아가는 과정이었던 것 같습니다.

도와주신 태우님, 우혁님, 수현님 그리고 정화님 다시 한번 감사드립니다.

이상으로 충돌 연구소장의 첫 번째 연구를 마치겠습니다.

다음 연구에서는 제발 한 번에 작동했으면 좋겠습니다.

...라고 쓰고 싶지만 아마 다음에도 뭔가 터지겠죠?

그럼 다음 연구에서 뵙겠습니다.
충돌 연구소장 퇴근합니당~~

profile
게임 개발자 꿈나무

2개의 댓글

comment-user-thumbnail
2026년 8월 24일

예수가 된 청년을 응원합니다
나날이 새롭도록 일일지져스 하십시오

답글 달기
comment-user-thumbnail
4일 전

지쟈스...
무서운 일입니다

답글 달기