[이득우의 언리얼 C++ 게임 개발의 정석] Chapter 15. 게임의 완성

수민·2023년 5월 17일
0
post-thumbnail

이득우의 언리얼 C++ 게임 개발의 정석을 읽고 개인 공부 목적으로 요약 정리한 글입니다!


👀 게임 데이터 저장과 로딩

SaveGame 시스템

SaveGame 시스템은 게임의 데이터를 저장하고 불러들일 수 있는 기능이다.
언리얼 엔진이 지원하니 언리얼 오브젝트를 상속받은 클래스를 생성하면 된다.

SaveGame 시스템을 사용하면,
에디터에서 저장할 경우 일반적으로 Saved/SaveGames/ 폴더에 저장된다.

슬롯 이름 : 각 저장 파일에 접근할 수 있는 고유 이름
슬롯 이름 별로 세이브 데이터를 구분할 수 있다.

void AMyPlayerState::SavePlayerData()
{
	UMySaveGame* NewPlayerData = NewObject<UMySaveGame>();
	NewPlayerData->PlayerName = GetPlayerName();
	NewPlayerData->Level = CharacterLevel;
	NewPlayerData->Exp = Exp;
	NewPlayerData->HighScore = GameHighScore;
	NewPlayerData->CharacterIndex = CharacterIndex;

	if (!UGameplayStatics::SaveGameToSlot(NewPlayerData, SaveSlotName, 0)) {
		HUNT_LOG(Error, TEXT("SaveGame Error"));
	}
}

void AMyPlayerState::AddGameScore()
{
	GameScore++;
	if (GameScore >= GameHighScore) {
		GameHighScore = GameScore;
	}
	OnPlayerStateChanged.Broadcast();
	SavePlayerData();
}

NewObject

언리얼 오브젝트 생성 시 NewObject 명령을 사용해서 생성한다.
이 오브젝트를 더 이상 사용하지 않으면,
Garbage Collector가 자동으로 언리얼 오브젝트를 소멸시켜준다.
오브젝트 삭제를 위해 delete하지 않아도 된다.


👀 시작, 종료 화면 제작

타이틀 화면 제작

타이틀 화면에서는 UI만 띄울거고,
필요한 것은
UI, 게임 모드, UI를 띄울 플레이어 컨트롤러

UI를 담당할 플레이어 컨트롤러를 C++ 클래스로 만든다
(UI 인스턴스를 만들고, 화면에 띄워서, 입력이 UI에 전달되도록 해준다)

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

	HUNT_CHECK(nullptr != UIWidgetClass);

	UIWidgetInstance = CreateWidget<UUserWidget>(this, UIWidgetClass);
	HUNT_CHECK(nullptr != UIWidgetInstance);

	UIWidgetInstance->AddToViewport();

	FInputModeUIOnly Mode;
	Mode.SetWidgetToFocus(UIWidgetInstance->GetCachedWidget());
	SetInputMode(Mode);
	bShowMouseCursor = true;
}

그리고

이 C++ 클래스로부터 블루프린트를 만들고

이 블루프린트의 UIWidgetClass를 UI로 설정한다.
그리고

GameModeBase를 블루프린트를 통해 새로 만들고

DefaultPawnClass를 Pawn으로
PlayerControllerClass를 BP_TitleUIPlayerController로 설정해준다

(블루프린트가 아니라 그냥 C++클래스로하면 UIWidgetClass가 설정이 안되니 주의.
C++ 클래스로 하려면 하드코딩해주거나, 에디터에서 설정하도록 프로퍼티 값을 변경하자.)

이렇게 하면

이렇게 잘 나온다.

위젯의 내용은

이렇게 되어있고,
C++로도 구현할 수 있다.

현재 월드에 있는 특정 타입을 상속받은 액터의 목록 구하는 함수 : TActorIterator<액터타입>

	for (TActorIterator<ASkeletalMeshActor> It(GetWorld()); It; ++It) {
		TargetComponent = It->GetSkeletalMeshComponent();
		break;
	}

이렇게 하면 ASkeletalMeshActor 타입을 상속받은 액터들의 목록에 대한 for문이 되는거다.

게임 중지

게임 시스템에 관련된 입력을 처리할 때는 PlayerController에서 처리한다.
플레이어 컨트롤러에서 게임 중지 관련 입력처리를 하면
빙의한 폰에 상관없이 입력을 처리할 수 있으므로,,

플레이 일시정지 함수 : PlayerController의 SetPause

마우스 커서 보이도록 설정하는 법 : bShowMouseCursor 속성 변경

void AMyPlayerController::OnGamePause()
{
	MenuWidget = CreateWidget<UMyGameplayWidget>(this, MenuWidgetClass);
	HUNT_CHECK(nullptr != MenuWidget);
	MenuWidget->AddToViewport(3);

	SetPause(true);
	ChangeInputMode(false);
}

void AMyPlayerController::ChangeInputMode(bool bGameMode)
{
	if (bGameMode) {
		SetInputMode(GameInputMode);
		bShowMouseCursor = false;
	}
	else {
		SetInputMode(UIInputMode);
		bShowMouseCursor = true;
	}
}

현재 뷰포트에 띄워진 UI 제거하는 함수 : RemoveFromParent

UI에서 자신을 관리하는 PlayerController의 정보를 알아오는 법 : GetOwningPlayer

void UMyGameplayWidget::OnResumeClicked()
{
	auto MyPlayerController = Cast<AMyPlayerController>(GetOwningPlayer());
	HUNT_CHECK(nullptr != MyPlayerController);

	RemoveFromParent();

	MyPlayerController->ChangeInputMode(true);
	MyPlayerController->SetPause(false);
}

결과 화면 제작

결과 화면 UI의 인스턴스를 시작할 때 만들어 놓고,
게임이 종료될 때 만들어진 인스턴스를 화면에 띄운다 (AddToViewport)

게임이 종료되는 조건은
GameState의 정보를 통해 결정되며,

게임이 종료되면
GameMode에서
폰의 입력을 멈추고,
PlayerController에게 결과 UI를 띄우라고 시킨다.

void AHunt_PrototypeGameModeBase::AddScore(AMyPlayerController* ScoredPlayer)
{
	...
	if (GetScore() >= ScoreToClear) {
		MyGameState->SetGameCleared();

		for (FConstPawnIterator It = GetWorld()->GetPawnIterator(); It; ++It) {
			(*It)->TurnOff();
		}

		for (FConstPlayerControllerIterator It = GetWorld()->GetPlayerControllerIterator(); It; ++It) {
			const auto MyPlayerController = Cast<AMyPlayerController>(It->Get());
			if (nullptr != MyPlayerController) {
				MyPlayerController->ShowResultUI();
			}
		}
	}
}

UI의 NativeConstruct
: AddToViewport 함수가 외부에서 호출될 때, UI 위젯이 초기화되며 호출된다.

그래서
PlayerController의 ShowResultUI 함수에서 AddToViewport 함수를 호출하는데,
그 전에 미리 UI 위젯이 GameState의 정보을 바인딩하도록 한다.

profile
우하하

0개의 댓글