Unreal - 트리거 매니저 ( 낙사 & 오토세이브 )

2026. 1. 21. 00:26·Unreal 프로젝트 다이어리/두번째 프로젝트

미리보기

구현내용

플레이어가 맵 이탈, 낙사, 혹은 강제 사망 상태에 진입하는 상황을

트리거 기반으로 처리하였으며 특정 구간 진입 시

현재 위치와 맵 정보를 자동으로 저장하는 오토 세이브 시스템을 구현했습니다

흔히 부르는 개념 세이브의 일종입니다

 

최종으로 기획된 트리거의 역할은 이와 같습니다

  • 낙사 처리 트리거
  • 강제 죽음 트리거
  • 오토 세이브 트리거
  • 듀토리얼 매니저 트리거

이번 글에서는 트리거 기반으로 처리한 낙사 시스템과 오토 세이브 기능의 구조 및 설계 의도를 다룹니다.

 

사용 클래스

클래스 이름 사용 목적
ManagerTrigger(액터) 맵 상에 배치되는 범용 트리거 액터
SaveFile(USaveGame) 게임 상태 데이터 컨테이너
게임 진행 상태를 순수 데이터 형태로 저장하는 역할
SaveManager(UObject) SaveFile을 실제로 디스크에 저장하고 불러오는
저장 로직 전담 클래스
ProjectGameInstance(Gameinstance) 게임 전반에서 공통으로 사용되는 전역 관리자 역할
LoadGameMode(AGameModeBase) 로딩맵에서 사용되는 로딩맵 전용 GameMode
게임 시작과 복귀의 관문 역할

 

구현

전반적인 세이브의 로직은 이전글에서 다루었습니다

이번에는 세이브 게임의 확장격인 오토세이브를 다룹니다

2025.12.02 - [Unreal 프로젝트 다이어리/두번째 프로젝트] - Unreal - 세이브 게임

 

Unreal - 세이브 게임

구현내용게임중 진행되는 세이브되어야하는 데이터들의 값 저장 구현목적언리얼에서는 게임을 실행할 때마다 이전 인스턴스가 모두 초기화되기 때문에, 별도의 조치를 취하지 않으면 게임 데

lucodev.tistory.com

 

플레이어가 특정 공간에 진입했을때 발생하는 게임 진행 이벤트를 중앙에서 제어하기 위해 설계된 액터가

ManagerTrigger입니다

간단하게 이벤트 단위의 관리자 개념입니다

UENUM(BlueprintType)
enum class EManagerTriggerType : uint8
{
	None,
	Fall,
	Tutorial,
	AutoSave
};
void AManagerTrigger::OnOverlapBegin(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	if (OtherActor == mainChar && OtherComp == capsuleComp)
	{
		if (triggerMap.Contains(triggerType))
		{
			triggerMap[triggerType](OtherActor);
			if (bOnce)
				triggerMap.Remove(triggerType);
		}
	}
}

void AManagerTrigger::InitTrigger()
{
	triggerMap.Add(EManagerTriggerType::Fall, [this](AActor* OtherActor) {
		mainChar->FallingDie();
		ChangeDeadCam();
		});

	triggerMap.Add(EManagerTriggerType::Tutorial, [this](AActor* OtherActor) {
		//mainGameInst-> 구현예정..
		});

	triggerMap.Add(EManagerTriggerType::AutoSave, [this](AActor* OtherActor) {
		mainGameInst->SavePlayerTransform(mainChar);
		});
}

 

원하는 트리거를 선택하여 사용합니다

 

오토세이브

오토 세이브 트리거를 통해 이벤트가 발생하면 현재 사용하고있는 게임인스턴스를 통해

현재 플레이어의 위치정보 및 소속 맵 정보를 저장하고 해당 위치로 시작했을때 플레이어가 페이드인 을 하는동안

위치를 변경하도록 설계하였습니다

 

그리고 언리얼 엔진은 PIE 환경에서 맵 이름앞에 UEDPIE_0 , UEDPIE_1 같은 접두사를 자동으로 붙혀서

접두사를 제거한 순수한 맵 이름만을 저장하도록 처리하였습니다

void UProjectGameInstance::SavePlayerTransform(AMainCharacter* mainCharacter)
{
	USaveFile* saveF = saveManager->currentSave;

	saveF->playerLoc = mainCharacter->GetActorLocation();
	saveF->playerRot = mainCharacter->GetActorRotation();

	FString MapName = mainCharacter->GetWorld()->GetMapName();

	MapName.RemoveFromStart(TEXT("UEDPIE_0_"));
	MapName.RemoveFromStart(TEXT("UEDPIE_1_"));

	saveF->savedMapName = FName(*MapName);

	saveManager->SaveGame();
}

void UProjectGameInstance::RestorePlayerTransform()
{
	APlayerController* pc = GetWorld()->GetFirstPlayerController();
	if (!pc)
		return;

	APawn* mayPawn = pc->GetPawn();
	if (!mayPawn)
		return;

	mayPawn->SetActorLocation(saveManager->currentSave->playerLoc);
	mayPawn->SetActorRotation(saveManager->currentSave->playerRot);
}

플레이어는 게임을 시작하면 Beginplay에서 페이드인이 재생되는 동안

RestorePlayerTransform으로 위치를 재설정하게됩니다

 

비동기 맵 로딩 시스템

언리얼 엔진에서 OpenLevel을 직접 호출할 경우, 맵 규모가 커질수록

로딩 과정에서 순간적인 프레임 드랍이나 화면 정지와 같은 UX 저하가 발생할 수 있습니다.

이를 개선하기위해 LoadPackageAsync를 활용하여 맵 패키지를 비동기 방식으로 사전 로딩 한 뒤

로딩이 완료된 시점에 실제 맵 전환을 수행하는 구조로 설계하였습니다

 

구조는 이와 같습니다

 

 

로딩맵에서 게임모드를 별도로 만들어 비동기 사전 로딩의 구현 방식입니다

void ALoadGameMode::BeginPlay()
{
	Super::BeginPlay();

	gameIst = Cast<UProjectGameInstance>(GetGameInstance());
	if (gameIst && gameIst->loadingWidget)
		gameIst->loadingWidget->AddToViewport();

    FName targetMap = NAME_None;

    if (!gameIst->saveManager->currentSave->savedMapName.IsNone())
        targetMap = gameIst->saveManager->currentSave->savedMapName;

	if (!targetMap.IsNone())
	{
		FString levelPath = FString::Printf(TEXT("/Game/Maps/%s.%s"),*targetMap.ToString(),*targetMap.ToString());
		LoadPackageAsync(levelPath,FLoadPackageAsyncDelegate::CreateUObject(this,&ALoadGameMode::OnGameLevelLoaded));
	}
}

void ALoadGameMode::OnGameLevelLoaded(const FName& packageName, UPackage* loadedPackage, EAsyncLoadingResult::Type result)
{
    if (gameIst && gameIst->loadingWidget)
        gameIst->loadingWidget->SetVisibility(ESlateVisibility::Visible); 

    if (result == EAsyncLoadingResult::Succeeded)
    {
        FTimerHandle TH_OpenLevelPack;
        FTimerDelegate TD_OpenLevelDel;
        TD_OpenLevelDel.BindLambda([this, packageName]()
            {
                FString mapName = packageName.ToString();
                UGameplayStatics::OpenLevel(this, FName(*mapName));
            });

        GetWorldTimerManager().SetTimer(TH_OpenLevelPack, TD_OpenLevelDel, 3.0f, false);
    }
}

 

낙사

이제 플레이어가 높은곳에서 떨어져 낙사 이벤트가 발생되는 지점에 트리거 타입이 Fall인 트리거 매니저를 깔아주고

트리거에 지정된 카메라에 카메라 시점을 변경하면서 플레이어의 행동을 처리해주었습니다

시점 변경은 SetViewTarget을 사용하였습니다

void AManagerTrigger::ChangeDeadCam()
{
	FViewTargetTransitionParams camParams;
	camParams.BlendTime = 0.6f;                 
	camParams.BlendFunction = VTBlend_EaseInOut;
	camParams.BlendExp = 2.0f;
	camParams.bLockOutgoing = true;

	mainPc->SetViewTarget(this, camParams);
}

 

플레이어의 행동은 모션매칭을 사용하고있기때문에 스키마를 추가한뒤

선택기 테이블에 FallingDie라는 State를 추가하여 낙사처리를 해주었습니다

 

모션매칭과 모션매칭 스키마또한 이전에 다룬적이 있으니 궁금하신분은 밑의 글에서 한번 구경해보시길바랍니다

2025.08.15 - [Unreal 프로젝트 다이어리/두번째 프로젝트] - Unreal - 모션매칭(Motion Matching) - 스키마 데이터 관리하기 (점프,달리기)

 

Unreal - 모션매칭(Motion Matching) - 스키마 데이터 관리하기 (점프,달리기)

1편과 이어집니다2025.08.09 - [Unreal5 프로젝트 다이어리2] - Unreal - 모션매칭(Motion Matching) - 기본이동 구현하기 Unreal - 모션매칭(Motion Matching) - 기본이동 구현하기Motion Trajectory플러그인을 설치해줍니

lucodev.tistory.com

결과물

낙사

 

오토세이브는 GIF파일로 설명이 불가능한거같네요 영상을 남깁니다

 

낙사를 한뒤 땅바닥에서 스폰하는게 아닌 마지막으로 오토세이브 된 위치에서 다시 스폰하게됩니다

 

저작자표시 비영리 변경금지 (새창열림)

'Unreal 프로젝트 다이어리 > 두번째 프로젝트' 카테고리의 다른 글

Unreal - 달리 줌 (Dolly - Zoom)  (0) 2026.01.25
Unreal - 상호작용 추가  (2) 2026.01.24
Unreal - 죽음 / 리스폰  (0) 2026.01.20
Unreal - 적 공격 간파하기  (2) 2026.01.16
Unreal - 가드 (Guard) / 체간 (Posture) 시스템  (4) 2026.01.12
'Unreal 프로젝트 다이어리/두번째 프로젝트' 카테고리의 다른 글
  • Unreal - 달리 줌 (Dolly - Zoom)
  • Unreal - 상호작용 추가
  • Unreal - 죽음 / 리스폰
  • Unreal - 적 공격 간파하기
lucodev
lucodev
언리얼 포폴개발 일기
  • lucodev
    루코 개발테이블
    lucodev
  • 전체
    오늘
    어제
    • 분류 전체보기 (236)
      • Unreal 프로젝트 다이어리 (132)
        • 첫번째 프로젝트 (73)
        • 두번째 프로젝트 (59)
      • Unreal 팁 (8)
      • Unreal 디버깅 (8)
      • C++ 프로그래머스 (52)
        • Stack,Queue (7)
        • Hash (4)
        • Heap (2)
        • Sort (5)
        • Exhaustive search (5)
        • Greedy (2)
        • BFS , DFS (7)
        • Graph (2)
        • Dynamic Programming (1)
        • C++ Math (2)
        • 기타 문제 (14)
      • C++ 백준 (5)
      • C++ 팁 (1)
      • 개인 코테 & 스타디 <비공개> (29)
        • 코드 개인보관함 (9)
        • 코딩테스트+@ (11)
        • 알고리즘 스타디 (6)
        • 알고리즘 스타디 과제 (3)
        • 비공개 (0)
  • 인기 글

  • 최근 글

  • 최근 댓글

  • 링크

  • 공지사항

  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 태그

    언리얼 비헤이비어트리
    unreal 상호작용
    언리얼 behaviortree
    언리얼 컷씬
    언리얼 파쿠르
    unreal npc
    언리얼 세키로
    unreal 파쿠르
    unreal 세키로
    언리얼 behavior tree
    unreal 인벤토리
    언리얼
    unreal inventory
    언리얼 상호작용
    언리얼 시퀀스
    unreal
    언리얼 인벤토리
    언리얼 ui
    언리얼 parkour
    언리얼 인터렉션
  • hELLO· Designed By정상우.v4.10.3
lucodev
Unreal - 트리거 매니저 ( 낙사 & 오토세이브 )
상단으로

티스토리툴바