PART 2 - 강의 2/4
텔레포트 프리로딩 구현
끊김 없는 장거리 이동을 위한 스트리밍 전략
01
텔레포트 문제점
프리로딩 없이 텔레포트할 때 발생하는 이슈
플레이어가 장거리 텔레포트할 때 타겟 영역이 로드되지 않은 상태면 빈 공간에 도착하거나 낙하/충돌 문제가 발생합니다.
문제 상황:
[플레이어 현재 위치] [텔레포트 목적지]
A B
● ?
┌─────────────┐ ┌─────────────┐
│ 로드됨 │ -----> │ 로드 안됨 │
│ (안전) │ 텔레포트 │ (위험!) │
└─────────────┘ └─────────────┘
결과:
- 지형이 없어서 낙하
- 충돌 메시 없음
- 액터 참조 실패
- 비주얼 팝인
02
TeleportManager 구현
프리로딩이 포함된 텔레포트 매니저
C++ - TeleportManager.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "TeleportManager.generated.h"
class AMyStreamingSourceActor;
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnTeleportReady);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnTeleportComplete);
UCLASS()
class MYGAME_API ATeleportManager : public AActor
{
GENERATED_BODY()
public:
// 텔레포트 전 타겟 위치 미리 로딩
UFUNCTION(BlueprintCallable, Category = "Teleport")
void PreloadTeleportDestination(FVector TargetLocation);
// 텔레포트 실행 (프리로딩 포함)
UFUNCTION(BlueprintCallable, Category = "Teleport")
void ExecuteTeleport(APawn* Pawn, FVector TargetLocation);
// 즉시 텔레포트 (프리로딩 완료 후)
UFUNCTION(BlueprintCallable, Category = "Teleport")
void TeleportNow(APawn* Pawn, FVector TargetLocation);
// 델리게이트
UPROPERTY(BlueprintAssignable)
FOnTeleportReady OnTeleportReady;
UPROPERTY(BlueprintAssignable)
FOnTeleportComplete OnTeleportComplete;
protected:
UPROPERTY()
TObjectPtr<AMyStreamingSourceActor> PreloadStreamingSource;
FVector PendingTeleportLocation;
TWeakObjectPtr<APawn> PendingTeleportPawn;
FTimerHandle PreloadTimerHandle;
void OnPreloadComplete();
void CleanupPreload();
};
C++ - TeleportManager.cpp
#include "TeleportManager.h"
#include "MyStreamingSourceActor.h"
void ATeleportManager::PreloadTeleportDestination(FVector TargetLocation)
{
// 타겟 위치에 스트리밍 소스 생성/이동
if (!PreloadStreamingSource)
{
FActorSpawnParameters SpawnParams;
SpawnParams.SpawnCollisionHandlingOverride =
ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
PreloadStreamingSource = GetWorld()->SpawnActor<AMyStreamingSourceActor>(
TargetLocation, FRotator::ZeroRotator, SpawnParams);
}
else
{
PreloadStreamingSource->SetActorLocation(TargetLocation);
}
PreloadStreamingSource->EnableStreaming();
UE_LOG(LogTemp, Log, TEXT("Preloading teleport destination: %s"),
*TargetLocation.ToString());
}
void ATeleportManager::ExecuteTeleport(APawn* Pawn, FVector TargetLocation)
{
if (!Pawn) return;
PendingTeleportLocation = TargetLocation;
PendingTeleportPawn = Pawn;
// 먼저 프리로드 시작
PreloadTeleportDestination(TargetLocation);
// 스트리밍 완료 대기 (로딩 화면 표시 가능)
GetWorldTimerManager().SetTimer(
PreloadTimerHandle,
this,
&ATeleportManager::OnPreloadComplete,
0.1f,
true);
}
void ATeleportManager::OnPreloadComplete()
{
if (PreloadStreamingSource && PreloadStreamingSource->IsStreamingComplete())
{
GetWorldTimerManager().ClearTimer(PreloadTimerHandle);
// 텔레포트 준비 완료 알림
OnTeleportReady.Broadcast();
if (APawn* Pawn = PendingTeleportPawn.Get())
{
TeleportNow(Pawn, PendingTeleportLocation);
}
}
}
void ATeleportManager::TeleportNow(APawn* Pawn, FVector TargetLocation)
{
if (!Pawn) return;
// 실제 텔레포트 수행
Pawn->SetActorLocation(TargetLocation);
// 프리로드 소스 정리
CleanupPreload();
// 텔레포트 완료 알림
OnTeleportComplete.Broadcast();
UE_LOG(LogTemp, Log, TEXT("Teleport complete to: %s"), *TargetLocation.ToString());
}
void ATeleportManager::CleanupPreload()
{
if (PreloadStreamingSource)
{
PreloadStreamingSource->DisableStreaming();
// 소스는 재사용을 위해 파괴하지 않음
}
}
03
로딩 UI 통합
프리로딩 중 사용자 피드백
C++ - 로딩 UI 연동 예제
// GameMode나 HUD에서 TeleportManager 이벤트 처리
void AMyGameMode::SetupTeleportCallbacks()
{
if (TeleportManager)
{
// 프리로딩 시작 시 로딩 화면 표시
TeleportManager->OnTeleportReady.AddDynamic(
this, &AMyGameMode::OnTeleportReadyHandler);
// 텔레포트 완료 시 로딩 화면 숨김
TeleportManager->OnTeleportComplete.AddDynamic(
this, &AMyGameMode::OnTeleportCompleteHandler);
}
}
void AMyGameMode::OnTeleportReadyHandler()
{
// 로딩 화면 숨기기 (선택적 - 텔레포트 직전)
}
void AMyGameMode::OnTeleportCompleteHandler()
{
// 로딩 화면 숨기기
if (APlayerController* PC = GetWorld()->GetFirstPlayerController())
{
if (AMyHUD* HUD = Cast<AMyHUD>(PC->GetHUD()))
{
HUD->HideLoadingScreen();
}
}
}
// 텔레포트 요청 시
void AMyGameMode::RequestTeleport(APawn* Pawn, FVector Location)
{
// 로딩 화면 표시
if (APlayerController* PC = GetWorld()->GetFirstPlayerController())
{
if (AMyHUD* HUD = Cast<AMyHUD>(PC->GetHUD()))
{
HUD->ShowLoadingScreen();
}
}
// 텔레포트 실행
TeleportManager->ExecuteTeleport(Pawn, Location);
}
UX 팁
로딩 시간이 짧으면 로딩 화면이 깜빡이는 느낌을 줄 수 있습니다. 최소 표시 시간을 설정하거나, 프로그레스 바로 진행 상황을 보여주는 것이 좋습니다.
04
고급: 다중 목적지 프리로딩
여러 잠재적 목적지를 동시에 프리로드
C++ - 다중 프리로딩
// 여러 워프 포인트를 미리 로드하는 경우
UCLASS()
class ATeleportHub : public AActor
{
GENERATED_BODY()
public:
// 플레이어가 허브 영역에 진입하면 모든 목적지 프리로드
void OnPlayerEnterHub(APawn* Player);
// 플레이어가 허브를 떠나면 프리로드 해제
void OnPlayerExitHub(APawn* Player);
protected:
UPROPERTY(EditAnywhere, Category = "Teleport")
TArray<FVector> DestinationLocations;
UPROPERTY()
TArray<TObjectPtr<AMyStreamingSourceActor>> PreloadSources;
};
void ATeleportHub::OnPlayerEnterHub(APawn* Player)
{
for (const FVector& Location : DestinationLocations)
{
FActorSpawnParameters SpawnParams;
AMyStreamingSourceActor* Source =
GetWorld()->SpawnActor<AMyStreamingSourceActor>(
Location, FRotator::ZeroRotator, SpawnParams);
if (Source)
{
Source->EnableStreaming();
PreloadSources.Add(Source);
}
}
}
void ATeleportHub::OnPlayerExitHub(APawn* Player)
{
for (AMyStreamingSourceActor* Source : PreloadSources)
{
if (Source)
{
Source->DisableStreaming();
Source->Destroy();
}
}
PreloadSources.Empty();
}
SUMMARY
핵심 요약
- 텔레포트 전 타겟 위치에 스트리밍 소스를 배치하여 미리 로드
- IsStreamingCompleted로 로딩 완료를 확인한 후 텔레포트 실행
- 로딩 UI를 통해 사용자에게 피드백 제공
- 텔레포트 완료 후 프리로드 소스 비활성화
- 워프 허브 등에서는 다중 목적지 프리로딩 고려
PRACTICE
도전 과제
배운 내용을 직접 실습해보세요
실습 1: 기본 텔레포트 프리로딩 구현
텔레포트 대상 위치에 임시 스트리밍 소스를 등록하고, IsStreamingCompleted()를 폴링하여 로딩 완료 후 플레이어를 이동시키는 기본 시스템을 구현하세요. 로딩 화면 표시도 추가합니다.
실습 2: 비동기 텔레포트 시스템
로딩 화면과 프로그레스 바를 표시하면서 비동기로 대상 영역을 프리로드하는 텔레포트 시스템을 구현하세요. FWorldPartitionStreamingSource를 활용하여 로딩 진행률을 추적합니다.
심화 과제
로딩 화면 없이 원거리 이동이 가능한 심리스 패스트 트래블을 구현하세요. 이동 경로를 따라 스트리밍 소스를 순차적으로 이동시키며, 카메라 전환과 페이드 효과를 조합하여 끊김을 최소화합니다.