[언리얼] CharacterMovementComponent 파이프라인-1-
https://imresearcher.tistory.com/39 에 이어서
[언리얼] 엔진 분석 Character Movement Component -0-
https://youtu.be/urkLwpnAjO0?si=j0MJuRO1m7Agyvzu [Unreal Engine] Do you need it? Intro to Series | Character Movement Component In-Depth 캐릭터 무브먼트 컴포넌트(CMC)란캐릭터로부터 전달된 인풋(Input)을 바탕으로
imresearcher.tistory.com
https://youtu.be/dOkuIvKCvpg?si=AN2E0FogsXFDIPLw
CharacterMovementComponent의 아키텍쳐
캐릭터에게 Input Vectors와 Events가 주어지면, Movement Mode를 바꿔 캐릭터의 Transform을 업데이트한다.
Movement Mode 설명
Movement Mode는 캐릭터의 물리적인 이동 상태를 결정한다.
- MOVE_Flying: 캐릭터가 공중에서 자유롭게 비행하는 모드. 중력이 적용되지 않음.
- MOVE_Falling: 캐릭터가 점프하거나 낙하할 때 중력의 영향을 받는 모드. 이 모드에서는 중력이 Velocity.Z 값에 적용되어 캐릭터가 점점 하강하게 된다.
Velocity를 변경하는 것만으로는 캐릭터가 점프나 낙하를 하지 않으며, 점프와 같은 동작이 이루어지려면 반드시 Movement Mode를 MOVE_Falling으로 전환해야 한다. 또한 비행 모드(MOVE_Flying)에서는 중력이 적용되지 않기 때문에, Velocity.Z 값을 변경하더라도 캐릭터가 위로 점프하거나 아래로 낙하하지 않는다. 즉, 캐릭터가 점프하려면 MOVE_Falling 상태로 변경해 중력의 영향을 받도록 만들어야 한다.
결론 : CharacterMovementComponent의 Jump 액션은 Velocity.Z의 값이 변경된 이후, Movement Mode를 MOVE_Falling으로 전환됨으로써 동작한다.
- Velocity.Z: 캐릭터가 위로 점프할 수 있도록 속도를 설정한다. 값은 일반적으로 양수이며, 클수록 캐릭터가 더 높이 점프한다.
- SetMovementMode(MOVE_Falling): 캐릭터의 상태를 MOVE_Falling으로 변경하여 중력의 영향을 받게 한다. 캐릭터가 점프 후 자연스럽게 떨어지게 된다.
Movement Mode가 바뀔 때 실행되는 Phys* 함수
Delta Time - 프레임 간격 당 시간
Acceleration - Input Vector의 강도
State Data, Compressed Flags
와 같은 데이터를 바탕으로 Phys* 함수가 Location, Rotation, Velocity, State Data를 변경함.
+ 여기에 SlideAlongSurface(), HandleImpact(), CalcVelocity() 등등 기타 함수가 적용됨.
+ Delta Time 자체가 실제 프레임보다는 값이 크기 때문에 시간 단위를 쪼개서 계산하는 sub stepping 작업이 진행됨. Phys* 함수 안에서 Delta Time이 잘개 쪼개진만큼 루프가 돈다고 함.
- 하지만 Phys* 함수가 실행되는 동안 이동상태가 변경되면 어쩌지?
StartNewPhysics(remainingTime, Iterations++) 실행 : 남은 시간 동안 새로운 이동함수 실행시키고 무한루프 안 돌게 실행횟수 체크함.
네트워킹의 경우
- Owning Client(본인) : 이동하고, 서버에게 확인차 데이터 보내고, 서버로부터 조정된 값을 받음.
- Server(서버) : 클라이언트 데이터를 받고, 이동시킨 후 Remote Clients들에게 해당 값 replicte하고(보냄), 클라이언트 조정이 필요하면 실행함.
- Remote Client(다른 플레이어) : 서버로부터 현재 상태값 받고, 위치를 보간함.
-> CMC는 이동에 대한 네트워킹 처리를 다해줌. 작업 시에는 Owning Client와 Server간의 상호작용을 더 신경쓰면 됨.
이동 파이프라인은 Client가 먼저 예측 움직임을 시도함으로써 진행된다.
Client가 입력을 받고 해당 데이터를 서버에 보낸 뒤 서버가 컨펌까지 한 뒤에 움직인다면, 서버로 데이터를 전송할 때의 핑, 그리고 서버에서 확정된 값이 돌아올 때의 핑까지의 시간 딜레이가 있어 매우 유효하지 못한 이동 시스템이 된다. 고로 입력과 동시에 Client도 먼저 움직임을 행하고, 서버에서 이동값을 처리할 때 문제가 없으면 해당 움직임을 유효, 성공으로 판정하도록 되어있다.
▼대략 이런 데이터를 Move때마다 서버에 보낸다. 서버도 동일하게 재현한다.
SavedMove
Time Stamp - Move의 실행시점으로 Id처럼 이용된다.
Default State Data (Transform, Control Rotation, Velocity, Delta Time, Acceleration)
Compressed Flags
Custom State Data
Client Pipleline

Tick으로 매 프레임마다 캐릭터의 인풋 Vector를 실행한다 -> Controlld Character Move에서 Input Vector를 바탕으로 캐릭터 가속(이동)한다. -> Perform Move에서 실질적으로 Apply Force/Impulse하여 캐릭터의 root motion을 변화시킨다. -> Start New Physics 실행해서 걸맞은 Movement Mode로 움직이게 한다.
-> 클라이언트 처리 끝나면 SavedMove 데이터를 가져다가 Replicate Move To Server한다. -> Server RPC가 서버 단에서 클라이언트 무브를 실행한다. 그리고 클라이언트 무브랑 맞는지 안 맞는지 확인.
Server Pipeline

Client가 서버로 RPC하면 이동 처리를 위한 준비하고 Move Autonomous와 Perform Move함수 통해 클라이언트와 동일하게 이동을 시행한다-> Server Move Handle Client Error를 통해 Client의 Output State가 서버단에서 실행한 Output State가 일치하는지 확인한다. -> 맞지 않으면 Client Adjust Position에서 클라이언트가 서버 단의 실행 결과로 조정되게끔 한다.
Client딴 이동 오류 정정은 어떻게 이루어지는가

Client가 계속해서 컨펌 안 된 Move들을 하고 있고, Server에서 오류가 난 시점의 이동 정정 값을 보내오면, 그 시점부터 고친 다음에 최근까지 발생된 컨펌 안된 Move들을 for each하여 수정하는 작업을 거침. 그래서 최근에 Client에서 실행된 이동값은 정정되고, 그 사이에 발생되는 약간의 오차 위치값은 언리얼 엔진이 자연스럽게 블렌딩해줌.
- 문제점
만일 움직임이 쿨다운이 있는 형태라면, 클라이언트에서 여러 차례의 'Perform Move'를 통해 시간 처리가 되었는데 서버에서는 한 번의 'Perform Move'만 하기 때문에 위치값 외의 데이터 오차가 발생할 수 있다.
- 해결안
SavedMove를 오버라이딩해서 커스텀 SavedMove 만들고 state 의존적인 데이터를 추가한다. (쿨다운타임 등)
Movement Safe Variables 이동 시에 안전한 변수들
SavedMove Data
Velocity & Acceleration
Compressed Flags
CharacterOwner
Not Chracter Owner properties (캐릭터 무기 같은 거.. 고로 커스텀 Movement를 만들 때 이런 변수들은 함부로 건드리면 안됨)