-
[UE5 | FPS] 진행 사항 정리언리얼엔진/FPS 프로젝트 2024. 8. 12. 01:36
거의 두 달만에 쓰는 글이다.
그동안 다양한 작업을 했지만, 별개의 글로 쓰기엔 내용이 부족한듯 해서 이렇게 한번에 묶어서 쓰게 됐다.
그동안 한 것을 대략 정리하면 다음과 같다.
1. 달리는 중에 무기를 발사하려고 하면 달리기를 멈춘 다음 걷기 상태에서 무기를 발사하게 함.
무기를 발사하는건 게임플레이 어빌리티로 구현했는데 어빌리티에서는 특정 게임플레이 태그가 제거될 때까지 기다리는 태스크를 사용할 수 있다.
캐릭터가 달리는 동안에는 달리기 게임플레이 태그를 추가하고 무기를 발사하는 어빌리티가 시작되면 달리기를 막는 게임플레이 태그를 추가해서 달리기를 멈추게 한다.
달리기가 멈춰서 게임플레이 태그가 제거되면 그 이후부터 어빌리티 작업을 진행한다.
어빌리티가 끝나면 달리기를 막는 태그도 제거되므로 캐릭터는 달릴 수 있게 된다.
연사의 경우에는 어빌리티가 계속 활성화 되지만, 단발의 경우에는 한발씩 발사할때마다 어빌리티가 끝나게 구현되어있다.
이러한 이유로 단발 사격이 끝나면 캐릭터가 즉시 달리게 되고, 다음 사격을 위해서는 다시 달리기가 멈출때까지 기다려야하는 문제가 있었다.
따라서 달리기를 막는 게임플레이 태그를 제거하기 전에 여유 시간을 주는 방식으로 해결했다.
2. 슬라이딩 추가.
물론 이것도 멀티플레이어에서도 작동한다.
슬라이딩의 경우에는 달리는 중에 앉기를 하면 작동되도록 했다.
따라서 앉기를 처리하는 로직에 슬라이딩 조건도 확인하게했다.
슬라이딩은 마찰을 줄여서 미끄러지게 하는 간단한 방법을 사용했다.
슬라이딩을 구현하는 과정에서 발견한 문제점은 다음과 같다.
2.1. 단순한 슬라이딩은 속도감이 없으므로 임펄스를 추가했지만, 적용되지 않는다.
문제의 원인은 임펄스를 추가하는 함수가 호출되는 위치였다.
위에서 언급했듯이 슬라이딩은 앉기를 처리할때 같이 확인하므로 임펄스도 이때 적용된다.
문제는 캐릭터 무브먼트 컴포넌트에서 앉기를 처리하는 로직(
UpdateCharacterStateBeforeMovement
)은 이미 임펄스를 처리(ApplyAccumulatedForces
)한 이후에 호출되고, 앉기를 처리한 후에는 임펄스 값을 초기화(ClearAccumulatedForces
)한다.따라서 아무리 높은 임펄스 값을 주어도 전혀 적용되지 않는다.
이 문제를 해결하기 위해 임펄스를 적용하는 코드를 참고해서
Velocity
벡터를 직접 수정하는 방법으로 해결했다.2.2. 앉기를 할때 카메라 높이를 보간하는 과정에서의 버그를 발견하고 수정함.
이건 내가 구현한 시스템에 종속적인 문제라서 자세하게 다루려면 어떻게 했는지부터 정리해야한다.
이 프로젝트에서는 앉기를 하면 캡슐 높이를 바로 줄이는게 아니라 카메라 높이가 목표 높이까지 이동해야 캡슐 높이를 줄인다.
물론 그 과정중에도 앉은 상태로 판정된다.
이렇게 구현한 이유를 설명하기 위해 앉은 상태에서만 지나갈 수 있는 낮은 높이의 장애물을 아래로 통과하는 경우를 예시로 들겠다.
만약 캡슐의 높이를 바로 줄인다면 앉기를 누르자마자 이동이 가능해지는데, 카메라의 높이는 보간되므로 아직 높은 위치에 있는 카메라가 장애물을 뚫고 들어가는 문제가 발생하게 된다.
하지만 높이 보간이 거의 끝난 뒤에 캡슐의 높이를 줄이면 이런 문제가 발생하지 않고 플레이어에게 더 설득력 있는 움직임을 보여준다.
머리의 위치가 충분히 내려가야 통과할수 있으니깐.
하지만 슬라이딩의 경우에는 빠른 속도로 이러한 장애물을 통과해야하므로 바로 캡슐의 높이를 줄여야 한다.
이렇게 구현하는 중에 높이를 보간할 목표 위치를 구하는 식과, 캡슐의 높이가 변경된 후에 카메라의 월드 위치를 유지하기 위해 상대 위치를 변경하는 식의 문제를 발견하여 수정했다.
3. 맨틀 기능 추가.
정확한 표현을 어떻게 해야할지 모르겠지만 모서리, 난간, 절벽 같은 부분을 잡고 올라가는 맨틀 무브먼트를 추가했다.
캐릭터 무브먼트 컴포넌트의 커스텀 무브먼트를 추가하는 방식으로 구현했다.
트레이싱을 통해 잡고 올라갈 수 있을만한 절벽의 모서리를 찾고, 목표 위치를 찾아서 그곳으로 이동하는 방식이다.
만약 목표 위치가 한계치보다 높다면 무기를 잠시 내리고 올라가지만, 한계치보다 낮다면 무기를 든 상태로 올라간다.
이것도 멀티플레이어에서 작동한다.캐릭터를 컨트롤하는 로컬 플레이어는 직접 트레이싱해서 해당 위치를 찾지만, 시뮬레이티드 프록시는 플레이어가 언제 난간을 오르고 싶어하는지 모르기 때문에 직접 트레이싱 하지 않는다.
클라이언트 입장에서 다른 플레이어의 시뮬레이티드 프록시 캐릭터가 모두 트레이싱 한다면 자원이 소모되는데다가 지연때문에 동기화 된 목표 위치를 찾지도 못한다.
대신에 목표 위치가 정해진 경우, 시뮬레이티드 프록시에게 그 위치를 레플리케이트 시켜서 무브먼트 모드를 변경하고 맨틀을 하게 했다.
나중에 카메라 애니메이션을 추가하게 되면 보기에 더 좋을듯 하다.
4. 플레이어의 사망과 리스폰 구현.
GAS의 어트리뷰트 셋에서 게임플레이 이펙트로 설정된 데미지 메타 어트리뷰트 값으로 조건에 따라 변경된 데미지를 처리하고 체력을 변경한 뒤에 0 이하가 되면 0으로 클램핑하고 사망처리를 한다.
해당 정보를 소스와 타깃 플레이어 컨트롤러에게 전달하여 소스는 HUD를 통해 킬 UI를 띄우고, 타깃은 제어중인 폰의 상태를 변경하고 입력 매핑 컨텍스트(IMC)도 사망 후에 사용되는 IMC로 변경한다.
이 정보는 게임 모드에도 전달되어 서버의 모든 컨트롤러에 킬 로그를 멀티캐스트하고, UI에 킬 로그를 띄우게 한다.
리스폰 타이머는 서버에서 작동하여 리스폰이 가능해지면 해당 클라이언트에게 리스폰이 가능하다고 전달해주고, 클라이언트에서 이 정보를 받으면 플레이어가 원할 때 서버에 리스폰을 요청하여 리스폰을 처리하게 된다.
리스폰이 되면 게임플레이 이펙트를 이용해서 체력을 가득 채우고, 무기도 기본 설정된 세팅대로 서버에 요청하여 새로 받게 된다.
참고로 플레이어 캐릭터가 사망하면 들고있던 무기는 떨어뜨리고, 집어넣었던 무기는 사라진다.
따라서 새로운 무기를 받아야할 필요가 있다.
그런데 게임을 시작하거나 리스폰 후에 프리셋 무기를 받는 작업을 할때 문제가 자주 발생해서 이 로직을 수정했다.
4.1. 프리셋 무기를 받는 로직 변경.
멀티플레이어에서 발생하는 문제였다.
GAS를 사용하기 때문에 무기는 각자의 어빌리티를 가지고있고, 플레이어에게 무기가 추가되면 플레이어의 어빌리티 시스템 컴포넌트에 무기의 어빌리티를 추가해야하는 등 무기를 추가하기전에 만족되어야하는 여러 조건들이 있었다.
따라서 무기를 추가하는 작업에 필요한 컴포넌트와 액터들의 초기화가 끝난 이후에 무기를 추가해야한다.
그중에 필요한게 플레이어 컨트롤러와 플레이어 스테이트였는데, 클라이언트에서는 이 두 액터를 레플리케이트 받아야하므로 이 두 액터가 유효해지는지는 시점이 언제인지는 불확실한 부분이 많다.
게다가 이 두 액터는 따로 레플리케이트 받으므로 더 까다로운 부분도 있었다.
이 과정은 프로젝트의 초반에 작업해서 위에 언급했던 여러 조건들을 확실하게 확인하지 않아 불안정한 편이었다.
이 로직을 다시 작업해서 필요한 모든 요소가 확실해진 이후에 서버에 프리셋 무기를 요청해서 그 후에 레플리케이트 받는 방법으로 변경했다.
무기를 굳이 레플리케이트 받는 이유는 이 프로젝트에서는 무기를 떨어뜨리거나 교체하는 기능을 추가할 예정이므로, 액터로 구현해서 동기화 되어야하기 때문이다.
무기를 레플리케이트 받은 후에도 확실하게 처리되어야 하므로 받은 무기를 검증하는 과정을 거치는데, 이 로직은 프로젝트 초기에 많은 고민을 해서 구현되었기 때문에 문제가 발생하지 않았다.
이런식으로 프리셋 무기를 요청해서 받기 때문에 리스폰 후에도 간단하게 프리셋 무기를 요청하면 끝이다.
5. 무기 드랍, 교체 구현.
이 내용은 다음 글에서 다루겠다.
https://mstone8370.tistory.com/46
[UE5 | FPS] 서버와 클라이언트의 동기화를 위한 고찰
이전 글의 마지막에 무기 드롭과 교체에 관한 내용을 다루겠다고 했다.관련 내용 중 서버와 클라이언트의 무기 슬롯 동기화에서 발생한 문제는 무엇인지, 이 문제를 어떻게 해결했는지, 이 방식
mstone8370.tistory.com
'언리얼엔진 > FPS 프로젝트' 카테고리의 다른 글
[UE5 | FPS] 서버와 클라이언트의 동기화를 위한 시행착오 (0) 2024.08.13 [UE5 | FPS] 멀티플레이에서 작동하는 달리기 구현 과정 (0) 2024.06.14 [UE5 | FPS] FGameplayEffectContext의 자식 구조체로 데미지 관련 정보 전달 (2) 2024.06.05 [UE5 | FPS] 히트 박스를 관리하기 위한 에디터 유틸리티 (1) 2024.06.02 [UE5 | FPS] 수평 FOV와 수직 FOV, 그리고 뷰모델 (0) 2024.05.08