이번에는 플레이어의 텔레포트 기능을 구현하려고 합니다.
처음 텔레포트 기능을 구현하려고 했을 때 가장 먼저 떠올릴 수 있는 방법은 AActor가 기본으로 제공하는 TeleportTo() 함수나
SetActorLocation()을 사용하는 것이다.
단순히 캐릭터의 위치만 변경하는 목적이라면 이 방식은 충분히 동작한다.
실제로 싱글플레이 환경이거나, 서버가 강제로 캐릭터를 특정 위치로 이동시키는 리스폰, 포탈 이동, 던전 입장 같은 상황에서는
TeleportTo() 만으로도 문제가 없는 경우가 많다.
하지만 이번에 구현하려는 기능은 단순 위치 이동이 아니라, 플레이어 입력을 기반으로 즉시 발동하는 텔레포트 스킬이었다.
예를 들어 플레이어가 특정 키를 누르면 캐릭터가 즉시 앞으로 이동하는 방식이다.
싱글플레이에서는 단순하지만, 멀티플레이 환경에서는 이 구조가 생각보다 복잡해진다.


구조는 다음과 같다.

Client에서 Actor의 TeleportTo() 함수를 사용하면 위치 동기화가 안되는 이유
멀티플레이어 위치의 최종 권한은 서버에 있다.
언리얼 멀티플레이에서는 보통 서버가 Actor의 최종 상태를 결정한다.
특히 Character의 위치는 서버 권한 구조를 따른다.
구조는 다음과 같다.
Client
└─ 입력을 보냄
└─ 로컬에서 이동을 예측할 수 있음
Server
└─ 클라이언트 이동 정보를 검증
└─ 최종 위치를 결정
└─ 필요하면 클라이언트 위치를 보정
즉, 클라이언트에서 Actor의 위치를 직접 바꿔도 서버가 그 변경을 인정하지 않으면 최종 위치로 유지되지 않고 서버상의 위치로 돌아오게 된다.
즉, Client에서 TeleportTo()를 호출하면 로컬에서만 위치가 바뀐다.
서버는 자신이 가진 위치를 기준으로 클라이언트를 보정하기 때문에 클라이언트에서 순간이동을 했더라도, 서버가 그 이동을 인정하지 않으면, 다시 서버위치로 보정된다.
왜 서버는 클라이언트의 TeleportTo()를 모를까?
Client가 TeleportTo 호출
↓
자동으로 Server에게 전달
↓
Server도 TeleportTo 실행
이런 구조라면 가능하다.
하지만, 지금 구조가 저렇지 않고 Client에서만 TeleportTo()함수를 사용한 것이기 때문에 위치가 동기화 되지 않는 것이다.
캐릭터 무브먼트 컴포넌트의 확장 ( RPC 기능을 내장하고 있는 컴포넌트)
- 기본 CharacterMovementComponent가 이미 해주는 것
걷기, 뛰기, 점프, 낙하, 웅크리기, 가속도, 속도, 위치 보정, 클라이언트 예측, ServerMove RPC 전송등이 있지만,
Teleport 같은 기능은 Actor에 자체에 있는 기능이라 CharacterMovementComponent에서 지원해주는 기능이 아니다.
따라서 이럴때는 CharacterMovementComponent의 기능을 확장하여 커스터마이징해서 Teleport 함수를 구현해야한다.
다음은 해당 기능을 구현하기 위한 작업이다.
- 1. Unreal Object의 인자가 있는 생성자 선언.

- 2. Client Character Data 변경


UCharacterMovementComponent는 TickComponment()를 통해 매 프레임 이동을 처리하고, 클라이언트 이동 정보를
SavedMove에 저장한 뒤 내부 ServerMove RPC 흐름을 통해 서버로 전달한다.
따라서 FNetworkPredictionData_Client_Character와 FSavedMove_Character를 커스텀하여 텔레포트 입력 정보를 저장하고, 이를 기존 CharacterMovement 네트워크 이동 흐름을 포함시켜 TeleportTo() 기반 텔레포트 기능을 구현하고자 한다.
- 3 Character Movement 변경


이 작업은 텔레포트 입력 상태를 CharacterMovement의 SavedMove 시스템에 저장하기 위해 필요합니다.
즉, 단순히 bPressedTeleport, bDidTeleport 변수를 MovementComponent에만 두는 게 아니라, 클라이언트가 이동한 한 프레임의 기록 안에 텔레포트 정보도 같이 저장하려는 작업입니다.
왜 FSavedMove_Character를 상속받아야 하나?
- 언리얼에서 CharacterMovement는 클라이언트 이동을 서버에 보낼 때, 매 프레임 이동 정보를 FSavedMove_Character에
저장합니다.
기본적으로는 다음과 같은 정보가 저장됩니다. ( 이동 입력, 가속도, 시간, 점프 여부, 웅크리기 여부, 위치 정보 등)
그런데 우리가 만든 텔레포트 정보는 기본 이동 정보가 아니기 때문에 이 값들은 언리얼 기본 FSavedMove_Character가
모르는 값이기 때문에, 직접 상속해서 저장 공간을 추가해야 합니다.
- Clear() : SavedMove가 재사용될 때 값을 초기화하는 함수.
- SetInitialPosition() : 이동 기록이 시작될 때 캐릭터의 현재 상태를 SavedMove에 저장하는 함수.
- GetCompressedFlags() : SavedMove에 저장된 텔레포트 정보를 서버로 보내기 위해 압축 플래그로 변환하는 함수.
흐름으로 보면 다음과 같습니다.
CharacterMovementComponent에 텔레포트 상태 존재
↓
SavedMove 생성
↓
SetInitialPosition()에서 상태 복사
↓
SavedMove가 이번 이동의 텔레포트 정보를 기억
최종 적으로 정리하면 다음과 같습니다 .
FSavedMove_Character는 클라이언트가 수행한 한 프레임의 이동 정보를 저장하는 클래스이다. 기본 클래스는 점프, 웅크리기 같은 기본 이동 상태만 알고 있기 때문에, 텔레포트와 같은 커스텀 이동 상태는 직접 저장할 수 없다.
따라서 FSavedMove_Character를 상속한 FABSavedMove_Character를 만들고, bPressedTeleport, bDidTeleport 값을 추가하였다.
이후 SetInitialPosition()에서 현재 MovementComponent의 텔레포트 상태를 SavedMove에 저장하고, GetCompressedFlags()에서 해당 값을 커스텀 플래그로 압축하여 기존 ServerMove RPC 흐름에 포함되도록 구성하였다.
신규 움직임 능력을 추가하는 방법

이 작업이 필요한 이유는 다음과 같다.
- 클라이언트가 만든 새로운 이동 상태를 서버에게 알려주기 위해서이다.
왜 플래그가 필요한가?
- 클라이언트에서 Teleprot 키를 눌렀을 때 다음과 같은 순서로 작업이 이루어집니다.
Client
└─ 텔레포트 입력 발생
└─ 로컬에서 먼저 텔레포트 예측
하지만 이 정보를 서버에게 알려주지 않으면 서버는 이렇게 생각할 수 있습니다.
Server
└─ 클라이언트가 갑자기 멀리 이동했네?
└─ 정상 이동 정보가 아니네?
└─ 기존 위치로 보정해야겠다.
그래서 클라이언트가 순간이동했다가 다시 원래 위치로 끌려갈 수 있습니다.
그래서 Custom Flag를 사용!
플래그를 사용하지 않으면 다음과 같은 문제가 발생합니다.
그래서 무슨 문제가 생기나?
클라이언트 위치는 텔레포트 때문에 멀리 가있습니다.
Client 위치: 앞으로 600 이동한 위치
그런데 서버는 일반 이동만 계산했기 때문에 그 위치까지 못 갑니다.
Server 위치: 기존 위치 근처
그러면 위치 차이가 생겨.
Client 위치 ≠ Server 위치
이때 서버는 자기 위치가 권한 있는 위치라고 판단해서 클라이언트를 보정해.
클라이언트에서 순간이동
↓
서버는 텔레포트 플래그를 받지 못함
↓
서버는 일반 이동만 처리
↓
서버 위치와 클라이언트 위치 불일치
↓
서버가 클라이언트 위치를 보정
↓
클라이언트가 다시 끌려감
그래서 플래그가 필요한 이유
플래그는 서버에게 이런 정보를 알려주는 역할입니다.
이번 ServerMove는 일반 이동이 아니라
텔레포트 입력이 포함된 이동입니다.
예를 들어:
if (bPressedTeleport)
{
Result |= FLAG_Custom_0;
}
이렇게 보내면 서버의 UpdateFromCompressedFlags()에서 다시 해석할 수 있습니다.
bPressedTeleport = (Flags & FSavedMove_Character::FLAG_Custom_0) != 0;
그 결과 서버는 이렇게 판단할 수 있습니다.
서버
└─ FLAG_Custom_0 확인
└─ 텔레포트 입력이 있었음을 인식
└─ 서버에서도 ABTeleport 실행
└─ 클라이언트와 비슷한 위치 결과 계산
여기까지 멀티플레이 환경에서 캐릭터 무브먼트 확장에 대해 알아보았습니다.
감사합니다!
'Unreal Project > Unreal Study' 카테고리의 다른 글
| Unreal StateTree로 NPC 대기와 순찰 AI 구현하기 (0) | 2026.06.08 |
|---|---|
| Unreal Engine Listen Server _ 03 ( 캐릭터 공격 구현 ) (0) | 2026.06.08 |
| 언리얼 팀프로젝트 회고 (0) | 2026.06.07 |
| Data_Asset 및 Quater View, Shoulder View 구현 (0) | 2026.02.26 |
| Unreal Collision에 관하여 (0) | 2025.10.31 |
