<그간의 작업을 하며 느낀 필자의 기분>
안녕하세요 여러분 긴시간 삽질을 통해서 죽지도 않고 다시 돌아왔습니다. 예상했던것보다 더 오랜시간이 걸렸습니다. 그래도 원하는 바를 이루어 내서 필자의 기분은 너무나 좋네요
우선은 결과물을 먼저 보여드리는게 좋을것 같습니다.
<필자의 마음을 편안하게 하는 부드러움>
저번과 다르게 발바닥의 끈끈이가 사라진듯 부드럽게 잘 올라가는 캐릭터가 보이실겁니다.
사실 구현은 했지만 엔진의 설계에 맞도록 구현을 했는지는 필자 본인도 알수가 없습니다. 엔진을 속속들이 다 알고있다면 모를 이야기지만 필자는 지금 읽고계시는 여러분과 마찬가지로 일개 사용자일 뿐이기 때문입니다.
저번에 작성한 글중에 일부러 코드를 안보여드린다는 글을 적은적이 있는데 누군가에게는 도움이 될법하지 않을까 싶기도 하고 여기까지 하는 사람이 얼마나 있겠냐는 심정에 열심히 작업한 내용을 올리려고 합니다. 물론 필자 스스로도 잘 정리를 해두어서 나중에 참고할 수 있는 정도를 기대하는것이긴 하지만요
일단 저번 포스팅에서 말씀드린 것들은 너무 많은 함수와 구조체가 필요로 하여서 필자 나름대로 필요한 부분만을 도출해 내서 입맛대로 코드를 재구성 해보았습니다. 하지만 재구성을 하면서 필요한것들을 몇가지 첨가하다 보니까 사실상 숫자상에서 크게 달라진 부분은 없는것 같은건 비밀아닌 비밀입니다.
일일히 나열하는것 보다는 하나하나 풀어가면서 필요한 순간에 연관된 내용을 정리해 나가는 방식으로 글을 쓰도록 하겠습니다.
우선 가장 크게 변한 부분은 TickComponent 함수입니다.
실질적인 중력이나 이동관련 부분을 SimulateMovement함수에서 처리하도록 옮겨서 매우 깔끔해진게 필자가 보기에 아주 좋습니다.
함수로 들어와 보면 FHitResult와 FRotator변수를 선언해줍니다. 이것들은 이번 시뮬레이션 동안 다른 함수에도 파견을 나가서 근무할 친구들이라 미리 선언해주는것입니다.
언리얼에서 제공해주는 CharacterMovement에서는 캐릭터의 이동상태가 Move_Walking일 경우에 중력을 체크 안하던 것으로 알고 있는데 필자또한 비슷하게 작성했습니다. 우선적으로 중력을 시뮬레이션 하고 그 다음에 이동을 처리합니다.
코드가 꽤나 길기 때문에 두부분으로 나눠서 진행을 하고 설명하기에 앞서서 한가지 함수를 먼저 이야기 하고 가겠습니다. IsMovingOnGround함수는 UNavMovementComponent클래스에 선언이 되어있지만 비어있는 가상함수이기 때문에 필요에 따라서 오버라이딩 하여 사용하는 함수입니다. 위와같은 내용은 언리얼에서 제공하는 CharacterMovement에서 고대로 가져온 친구이기 때문에 큰 설명이 필요없으리라 믿습니다.
IsMovingOnGround함수를 통해 현재 캐릭터의 이동상태를 확인하여 걷는 상태가 아닐경우에 중력을 통해 밑으로 떨어져야 하니까 Velocity에 중력값을 계산해서 대입합니다.
자연스럽게 SafeMoveUpdatedComponent를 사용하고 Hit결과 부딪힌 물체가 있고 IsWalkable함수의 반환값이 true면 CurrentFloor를 세팅해주고 캐릭터의 이동상태가 MOVE_Walking이 아니라면 MOVE_Walking으로 바꿔줍니다. 이후 충돌점으로부터 땅에서 Root컴포넌트가 떨어져야 할만큼 Z값을 조정해서 다시 대입해줍니다.
만약 부딪힌 물체가 없다면 여전히 공중에서 자유롭게 낙하중이기 때문에 RootComponent를 편안히 이동시켜주시면 됩니다.
이번에 두가지 함수가 나왔는데 IsWalkable과 SetFromSweep입니다. 우선은 IsWalkable 함수를 먼저 차근차근 알아보도록 하겠습니다.
이 함수에서는 중력을 통해 밟은 물체에 대해서 걸어다닐수 있는 물체인지 판단을 해주는 역할을 합니다.
필자도 내부에 있는 내용을 정확히 이해하고 있는것은 아니지만 충돌한 면의 Normal벡터를 이용하여 걸어다닐수 있는 높이값을 계산하여서 결과를 bool값으로 반환해줍니다.
SetFromSweep함수는 들어온 매개변수를 이용해서 CurrentFloor를 설정해주는 역할을 합니다.
비교적 다른건 이해하기 어려운부분은 적지만 Sweep에 대한 부분은 필자가 아직 잘 모르기 때문에 자세히 설명해 드릴수 없는점 양해해 주시면 감사하겠습니다.
이로써 이번에 사용된두가지 함수를 알아보았고 이제 다음으로는 중력처리 당시 IsMovingOnGround함수의 결과값이 true일때에 처리하는 부분을 알아보도록 하겠습니다.
캐릭터 이동상태가 바닥에 붙어서 움직이고 있다면 중력을 적용할필요는 없고 바닥의 높낮이에 맞춰서 캐릭터의 위치를 동기화 시켜주기만 하면 됩니다. 별로 크게 어려운 부분은 아니지요 어떤 방식을 하느냐에 따라서 달라지긴 하지만 말입니다.
필자는 언리얼 엔진에서 사용했듯이 LineTraceSingleByChannel(&)함수를 이용하겠습니다.
출처를 따라가 보시면 Hit결과 구조체의 멤버변수들이 무엇을 의미하는지도 확인할수 있으니 꼭 한번 보시기 바랍니다.
필자의 경우 RootComponent가 바닥에서 어느정도 거리가 있기 때문에 그 거리만큼 선 시작점 위치를 내려주어야 하기때문에 GroundOffsetZ를 썼지만 이 경우 너무 딱 달라붙어서 선충돌 검사를 해야할 대상을 지나쳐 버리는 일이 간혹 발생하는 바람에 캡슐로부터 받아온 PawnHalfHeight값을 두배로 하여 이용했습니다.
그리고 TraceDist변수는 쉽게 말해서 이번 프레임에 바닥을 확인할 최대 거리를 의미하며 2.4f 라는 수는 언리얼에서 고정적으로 쓰고있는 변수의 값이길래 그대로 하드코딩으로 넣었습니다.
if문을 보시면 두개를 걸어두었는데 혹시 몰라서 두개를 걸어둔것이니 읽고계신 여러분은 bBlockingHit만 확인하셔도 충분하시리라 생각됩니다.
선충돌이 정상적으로 작동했다면 떨어지다가 바닥에 부딪혔을때와 별로 다를것은 없습니다. Hit결과값을 통해서 CurrentFloor를 새로 지정해주고 부딪힌 위치를 기반으로 캐릭터가 바닥에 잘 붙어있도록 위치값을 좀 조정해주면 끝입니다.
만일 선충돌이 일어나지 않았다면 그건 곧 내려갈수 있는 계단이나 경사의 높이를 지나쳐서 떨어지고 있다는 의미가 되기때문에 캐릭터의 이동상태가 MOVE_Falling아니라면 MOVE_Falling으로 바꿔주고 CurrentFloor를 Clear시킵니다. 왜냐하면 현재 밟고있는 바닥은 존재하지 않고 영원한 나락으로 떨어지기 시작했기 때문이지요
이제 중력에 관련된 내용을 열심히 설명했으니까 본격적으로 지형 이동시에 높낮이로 생기는 문제를 해결한 이동코드를 설명해야합니다.
설명해야하는게 맞는데 이거 쓰는데도 시간이 너무 오래걸리고 말았네요. 오늘은 좀 쉬면서 다시한번 정리하고 내일 나머지 부분을 올리도록 하겠습니다.
<포스팅을 끝낸 필자>
'프로그래밍 > 언리얼' 카테고리의 다른 글
언리얼로 만들어보는 RPG - 캐릭터 구현(7) (2) | 2019.01.29 |
---|---|
언리얼로 만들어보는 RPG - 캐릭터 구현(6) (0) | 2019.01.10 |
언리얼로 만들어보는 RPG - 캐릭터 구현(4) (0) | 2019.01.06 |
언리얼로 만들어보는 RPG - 캐릭터 구현(3) (0) | 2019.01.02 |
언리얼로 만들어보는 RPG - 캐릭터 구현(2) (0) | 2018.12.28 |