콘텐츠로 이동

UE5 Network Prediction Plugin — 예측 이동 구현

Network Prediction Plugin(NP)은 UE5에서 실험적으로 도입된 데이터 중심 네트워크 예측 프레임워크입니다. 기존 CharacterMovementComponent의 한계(커스터마이징 어려움, 모노리식 구조)를 극복하고, 임의의 시뮬레이션 상태에 클라이언트 예측과 서버 조정을 적용할 수 있습니다.


Edit > Plugins > Network Prediction → 활성화 (실험적)
Build.cs:
PublicDependencyModuleNames.AddRange(new[]
{
"NetworkPrediction",
"NetworkPredictionExtras",
});

#include "NetworkPredictionTypes.h"
// 입력 상태: 클라이언트가 매 틱 전송
struct FMyInputCmd
{
FVector2D MoveInput; // 이동 방향
bool bJump = false;
bool bSprint = false;
void NetSerialize(FArchive& Ar)
{
Ar << MoveInput;
Ar.SerializeBits(&bJump, 1);
Ar.SerializeBits(&bSprint, 1);
}
};
// 동기 상태: 서버가 권위를 가지는 시뮬레이션 상태
struct FMySyncState
{
FVector Location;
FVector Velocity;
FRotator Rotation;
bool bIsGrounded = true;
bool ShouldReconcile(const FMySyncState& Auth) const
{
// 서버 상태와 예측 상태 차이가 임계값 초과 시 조정
return FVector::DistSquared(Location, Auth.Location) > 25.f;
}
void NetSerialize(FArchive& Ar)
{
Ar << Location << Velocity << Rotation;
Ar.SerializeBits(&bIsGrounded, 1);
}
};
// 보조 상태: 클라이언트에서 보간되는 비예측 데이터
struct FMyAuxState
{
float StaminaLevel = 100.f;
float Health = 100.f;
void NetSerialize(FArchive& Ar)
{
Ar << StaminaLevel << Health;
}
};

#include "NetworkPredictionSimulation.h"
struct FMyMovementSimulation
{
// 핵심: 시뮬레이션 틱 (클라이언트/서버 공통 실행)
static void Tick(
float DeltaTime,
const FMyInputCmd& Input,
const FMySyncState& InputState,
FMySyncState& OutputState,
const FMyAuxState& AuxState)
{
// 이동 계산 (결정론적이어야 함)
FVector Acceleration = FVector(Input.MoveInput.X, Input.MoveInput.Y, 0.f)
* 600.f;
// 중력
FVector Gravity = InputState.bIsGrounded
? FVector::ZeroVector
: FVector(0.f, 0.f, -980.f);
// 속도 통합
OutputState.Velocity = InputState.Velocity
+ (Acceleration + Gravity) * DeltaTime;
// 스프린트
if (Input.bSprint && AuxState.StaminaLevel > 0.f)
OutputState.Velocity *= 1.8f;
// 최대 속도 제한
OutputState.Velocity = OutputState.Velocity.GetClampedToMaxSize(700.f);
// 위치 통합
OutputState.Location = InputState.Location
+ OutputState.Velocity * DeltaTime;
// 점프
if (Input.bJump && InputState.bIsGrounded)
OutputState.Velocity.Z = 500.f;
OutputState.Rotation = InputState.Rotation;
OutputState.bIsGrounded = InputState.bIsGrounded; // 콜리전 처리 필요
}
};
// 타입 등록 매크로
DEFINE_NETWORK_PREDICTION_TYPE_OUTER(
FMyInputCmd, FMySyncState, FMyAuxState,
FMyMovementSimulation);

#include "NetworkPredictionComponent.h"
UCLASS()
class AMyCharacter : public ACharacter
{
GENERATED_BODY()
UPROPERTY(VisibleAnywhere)
UNetworkPredictionComponent* NPComp;
public:
AMyCharacter()
{
// 기존 CharacterMovement 비활성화 (NP 사용 시)
GetCharacterMovement()->SetActive(false);
NPComp = CreateDefaultSubobject<UNetworkPredictionComponent>(
TEXT("NetworkPrediction"));
}
virtual void BeginPlay() override
{
Super::BeginPlay();
// 시뮬레이션 초기화
FMySyncState InitialState;
InitialState.Location = GetActorLocation();
InitialState.Velocity = FVector::ZeroVector;
NPComp->InitializeSimulation<FMyMovementSimulation>(
this, InitialState);
}
// 입력 생성 (매 틱)
virtual void ProduceInput(
int32 SimFrame,
FMyInputCmd& Cmd)
{
// 플레이어 입력 읽기
Cmd.MoveInput.X = GetInputAxisValue("MoveForward");
Cmd.MoveInput.Y = GetInputAxisValue("MoveRight");
Cmd.bJump = GetInputAxisValue("Jump") > 0.5f;
Cmd.bSprint = GetInputAxisValue("Sprint") > 0.5f;
}
};

// Cue: 점프/착지 이펙트처럼 예측은 안 하지만 표시해야 하는 이벤트
struct FJumpCue
{
FVector Location;
float Intensity = 1.f;
static void OnActive(
const USceneComponent* Owner,
const FJumpCue& Cue)
{
// 착지 이펙트, 사운드 재생 (예측 불필요)
UGameplayStatics::SpawnEmitterAtLocation(
Owner->GetWorld(),
LandingParticle,
Cue.Location);
}
};

항목CharacterMovementComponentNetwork Prediction Plugin
상태모노리식타입 분리 (Input/Sync/Aux)
커스터마이징오버라이드 복잡Tick 함수만 구현
결정론부분적강제 (필수)
성숙도안정실험적
복잡도낮음높음

Network Prediction Plugin은 아직 실험적이므로 프로덕션 적용 전 안정성을 충분히 검증하세요. 시뮬레이션 Tick 함수는 **결정론적(deterministic)**이어야 합니다 — 같은 입력과 상태에 대해 항상 같은 결과를 내야 합니다. ShouldReconcile에서 위치 오차가 임계값을 넘을 때만 서버 조정이 일어나도록 튜닝해 네트워크 트래픽을 최소화하세요.