Unreal - 새로하기, 이어하기 메인메뉴 만들기

2025. 5. 29. 18:50·Unreal5 프로젝트 다이어리

게임을 시작했을때 처음에 볼 새로하기, 이어하기, 게임종료 기능이 있는 메인메뉴를 만들어보도록하겠습니다

일단 사용할 맵을 만들어줍니다

 

사용할 맵을 제작해주었습니다

 

원하는곳에 CineCamera를 배치후 원하는 뷰를 Pilot해서 시점을 지정합니다

원하는 시점에 화면을 고정하고싶으면 플레이어컨트롤러에서 카메라로 시점을 변경하여야합니다

 

플레이어컨트롤러를 만들어줍니다 그리고

Iterator로 월드상에 배치된 카메라중에 UPROPERTY로 선언된 cameraActorTag의 태그이름과 동일한

카메라를 찾아 그 카메라로 시점을 변경하겠습니다

UCLASS()
class BLASTERDREAM_API AMainMenuController : public APlayerController
{
	GENERATED_BODY()
	
public:
	AMainMenuController();
	virtual void BeginPlay() override;

	UPROPERTY(EditAnywhere, Category = "MySettings")
	FName cameraActorTag;
};

필요한 헤더 추가해줍니다

#include "Kismet/GameplayStatics.h"
#include "Camera/CameraActor.h"
#include "EngineUtils.h"
void AMainMenuController::BeginPlay()
{
	Super::BeginPlay();
	UWorld* mainWorld = GetWorld();
	for (TActorIterator<ACameraActor> it(mainWorld); it; ++it)
	{
		ACameraActor* mainCamera = *it;
		if (mainCamera->ActorHasTag(cameraActorTag))
		{
			SetViewTargetWithBlend(mainCamera, 0.f);
			break;
		}
	}
}

Uproperty값 FName값을 MainMenuCamera로 세팅해줍니다

 

월드상에 배치된 카메라에 태그를 붙혀주고 태그의 이름을 MainMenuCamera로 변경해줍니다

 

 

사용하고있는 컨트롤러를 적용해줍니다

 

현재까지 세팅이 완료되었으면 게임이 시작되었으면 해당 CineCamera로 시점이 변경되어 시작됩니다

사용할 위젯을 만들어주고 플레이어 컨트롤러에서 띄웁니다

마우스를 띄우고 Input모드를 Ui모드로 변경합니다

UPROPERTY(EditAnywhere, Category = "MySettings")
TSubclassOf<UStartMainMenuWidget> startMainMenuWidgetClass;

UStartMainMenuWidget* startMainMenuWidget;
startMainMenuWidget = CreateWidget<UStartMainMenuWidget>(this, startMainMenuWidgetClass);
if (startMainMenuWidget)
{
	startMainMenuWidget->AddToViewport();
	FInputModeUIOnly InputMode;
	SetInputMode(InputMode);
	bShowMouseCursor = true;
}

위젯에는 위젯애니메이션을 적용시켜주었습니다

2025.04.04 - [Unreal5 프로젝트 다이어리] - Unreal 캐릭터 - 위젯애니메이션

 

Unreal 캐릭터 - 위젯애니메이션

스킬의 위젯블루프린트 애니메이션을 통해 스킬쿨타임을 시각적으로 보여주는걸 만들어보자해당 애니메이션을 원하는객체를 선택후좌측하단에 있는 애니메이션을 열고+애니메이션 해서 노드

lucodev.tistory.com

 

 

 

게임시작버튼을 클릭하면 카메라의 위치가 좌측에있는 제단으로 변경되고 새로하기 이어하기 기능이 나오도록 해보겠습니다

게임시작을 누르면 좌측으로 카메라가 이동하게 해보겠습니다

시점을 변경하는 시퀀서를 제작해줍니다

버튼을 클릭하면 해당 시퀀스가 실행되도록 하겠습니다

만약 시퀀스가 실행하면 시퀀스가 끝나버리면 원래 카메라 위치로 변경되버립니다

위치가 변경되면 카메라의 시점을 유지해줄 홀딩용 카메라를 만들어줍니다

 

카메라를 구분하기위한 태그도 달아줍니다

 

버튼바인드쪽입니다

void UStartMainMenuWidget::NativeConstruct()
{
	Super::NativeConstruct();
	if (Button_GameStart)
	{
		Button_GameStart->OnHovered.AddDynamic(this, &UStartMainMenuWidget::OnHoverGameStartButton);
		Button_GameStart->OnUnhovered.AddDynamic(this, &UStartMainMenuWidget::OnUnHoverGameStartButton);
		Button_GameStart->OnClicked.AddDynamic(this, &UStartMainMenuWidget::OnClickGameStartButton);
	}
	if (Button_GameEnd)
	{
		Button_GameEnd->OnHovered.AddDynamic(this, &UStartMainMenuWidget::OnHoverGameEndButton);
		Button_GameEnd->OnUnhovered.AddDynamic(this, &UStartMainMenuWidget::OnUnHoverGameEndButton);
		Button_GameEnd->OnClicked.AddDynamic(this, &UStartMainMenuWidget::OnClickGameEndButton);
	}
}

 

 

버튼을 클릭하면 처음의 위젯의 캔버스패널(CanvasPanel_Main)의 하이어라키로 달려있는 모든위젯은 숨겨지며

시퀀스를 재생 그리고 시퀀스가 끝나면 OnMove2PannelSequenceFinished함수를 실행하여 맵상의 cameraActorTag를 달고있는 카메라로 시점이 전환됩니다

void UStartMainMenuWidget::OnClickGameStartButton()
{
	FMovieSceneSequencePlaybackSettings playSetting;
	ALevelSequenceActor* sequenceActor = nullptr;
	playSetting.bAutoPlay = false;
	ULevelSequencePlayer* sequenceToGamePlayer = ULevelSequencePlayer::CreateLevelSequencePlayer(GetWorld(), gameStartButtonClickSequence, playSetting, sequenceActor);

	CanvasPanel_Main->SetVisibility(ESlateVisibility::Collapsed);

	sequenceToGamePlayer->OnFinished.AddDynamic(this, &UStartMainMenuWidget::OnMove2PannelSequenceFinished);
	sequenceToGamePlayer->Play();
}
void UStartMainMenuWidget::OnMove2PannelSequenceFinished()
{
	UWorld* mainWorld = GetWorld();
	APlayerController* playerCon = UGameplayStatics::GetPlayerController(mainWorld, 0);
	AMainMenuController* mainMenuCon = Cast<AMainMenuController>(playerCon);

	for (TActorIterator<ACameraActor> it(mainWorld); it; ++it)
	{
		ACameraActor* mainCamera = *it;
		if (mainCamera->ActorHasTag(cameraActorTag))
		{
			mainMenuCon->SetViewTargetWithBlend(mainCamera, 0.f);
			break;
		}
	}
}

 

 

돌아가기도 구현해줍니다

 

 

이어하기를 한다는건 세이브가 된 위치기준점으로 해당맵 해당위치 해당방향으로 다시 복귀하면됩니다

.sav 저장의 로직을 플레이어의 방향 위치 맵 이름을 추가해줍니다

//loc, rot, map
saveGameInstance->playerLastLocation = player->GetActorLocation();
saveGameInstance->playerLastRotation = player->GetActorRotation();
FString mapName = GetWorld()->GetMapName();
mapName.RemoveFromStart(GetWorld()->StreamingLevelsPrefix);
saveGameInstance->lastMapName = mapName;
UGameplayStatics::SaveGameToSlot(saveGameInstance, saveGameInstance->saveSlotName, saveGameInstance->saveIndex);

 

불러오기함수를 만듭니다

불러오기함수의 위치는 게임인스턴스에 만들겠습니다

void UStatGameInstance::LoadPlayerData()
{
	if (UGameplayStatics::DoesSaveGameExist(TEXT("PlayerSaveData"), 0))
	{
		UProjectSaveGame* loadedData = Cast<UProjectSaveGame>(UGameplayStatics::LoadGameFromSlot(TEXT("PlayerSaveData"), 0));
		if (loadedData)
		{
			FString currentMapName = GetWorld()->GetMapName();
			currentMapName.RemoveFromStart(GetWorld()->StreamingLevelsPrefix);

			//저장맵이 지금맵이랑 다르면 오픈
			if (currentMapName != loadedData->lastMapName)
			{
				UGameplayStatics::OpenLevel(GetWorld(), FName(*loadedData->lastMapName));
				return;
			}
			else
			{
				saveLocation = loadedData->playerLastLocation;
				saveRotator = loadedData->playerLastRotation;
				bShouldRestoreTransform = true;
			}
		}
	}
}

 

불러오기는 계속하기 버튼을 눌렀을때 사용됩니다

//이어하기
void UStartMainMenuWidget::OnClickContinueGameButton()
{
	APlayerController* pC = UGameplayStatics::GetPlayerController(this, 0);
	fadeWidgetInstance = CreateWidget<UFadeInOutWidget>(pC, fadeWidget);
	//no save data
	if (!UGameplayStatics::DoesSaveGameExist(TEXT("PlayerSaveData"), 0))
	{
		CanvasPanel_NoSav->SetVisibility(ESlateVisibility::Visible);
		return;
	}
	if (fadeWidgetInstance)
	{
		fadeWidgetInstance->AddToViewport();
		FWidgetAnimationDynamicEvent endEventSW;
		endEventSW.BindDynamic(this, &UStartMainMenuWidget::openLevel);
		fadeWidgetInstance->BindToAnimationFinished(fadeWidgetInstance->FadeOut, endEventSW);
	}
	fadeWidgetInstance->PlayFadeOut();
}

 

void UStartMainMenuWidget::openLevel()
{
	UStatGameInstance* gameInstance = Cast<UStatGameInstance>(GetWorld()->GetGameInstance());
	if (gameInstance)
	{
		gameInstance->LoadPlayerData();
	}
}

 

새로하기는 .Sav데이터를 삭제시키고 새로운맵으로 이동하면되겠습니다

DoesSaveGameExist함수로 .sav파일의 존재유무를 확인

DeleteGameInSlot으로 삭제합니다

void UStartMainMenuWidget::OnClickNewGameButton()
{
	FString SlotName = TEXT("PlayerSaveData");
	int32 UserIndex = 0;

	if (UGameplayStatics::DoesSaveGameExist(SlotName, UserIndex))
	{
		UGameplayStatics::DeleteGameInSlot(SlotName, UserIndex);
	}

	if (!targetLoadingMap.IsEmpty())
	{
		UGameplayStatics::OpenLevel(this, FName(*targetLoadingMap));
	}
}

 

 

종료하기버튼은 QuitGame함수로 게임을 끝냅니다

void UStartMainMenuWidget::OnClickGameEndButton()
{
	APlayerController* playerController = UGameplayStatics::GetPlayerController(this, 0);

	UKismetSystemLibrary::QuitGame(this, playerController, EQuitPreference::Quit, false);
}

 

세이브를 하면 .sav파일이 생기고 해당 파일이 저장된 상태로 시작

새로하기를 하면 세이브파일을 지우고 처음 마을맵부터 시작

이어하기를하면 .sav파일에 저장된 위치와 hp mp부터 시작됩니다

 

 

 

 

 

 

'Unreal5 프로젝트 다이어리' 카테고리의 다른 글

Unreal - Foot Step Sound  (0) 2025.05.30
Unreal - 위젯에 동영상 파일 추가하기 (인트로)  (0) 2025.05.30
Unreal - 던전 클리어 위젯 만들기  (0) 2025.05.25
Unreal - 플레이어 리스폰  (0) 2025.05.24
Unreal - 던전진행도 위젯 만들기 (스칼라 파라미터 조절하기)  (0) 2025.05.23
'Unreal5 프로젝트 다이어리' 카테고리의 다른 글
  • Unreal - Foot Step Sound
  • Unreal - 위젯에 동영상 파일 추가하기 (인트로)
  • Unreal - 던전 클리어 위젯 만들기
  • Unreal - 플레이어 리스폰
lucodev
lucodev
커피와 노트북 그리고 개발
  • lucodev
    루코 개발테이블
    lucodev
  • 전체
    오늘
    어제
    • 분류 전체보기 (130) N
      • Unreal5 프로젝트 다이어리 (73)
      • Unreal5 프로젝트 다이어리2 (9) N
      • Unreal 팁 (8)
      • Unreal 디버깅 (8)
      • C++ 프로그래머스 다이어리 (24)
        • Stack (3)
        • Hash (4)
        • Heap (2)
        • Sort (4)
        • Exhaustive search (0)
      • 코드 개인보관함 (8)
  • 인기 글

  • 최근 글

  • 최근 댓글

  • 링크

  • 공지사항

  • 블로그 메뉴

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

    언리얼 behaviortree
    unreal 로딩
    unreal look at
    언리얼 behavior tree
    unreal sequence
    언리얼 로딩
    unreal loading
    언리얼 모션매칭
    언리얼 motionmatching
    언리얼 look at
    언리얼 페이드 아웃
    언리얼 컷씬
    unreal 컷씬
    언리얼
    언리얼 로딩창
    unreal 모션매칭
    언리얼 비헤이비어트리
    언리얼 foot step
    언리얼 시퀀스
    unreal 시퀀스
  • hELLO· Designed By정상우.v4.10.3
lucodev
Unreal - 새로하기, 이어하기 메인메뉴 만들기
상단으로

티스토리툴바