오늘은 게임의 중요한 기능인 세이브 파일을 구현하도록 하겠다
언리얼 엔진은 게임 데이터를 저장하고 불러들이는 기능을 가진 SaveGame
클래스를 제공한다
세이브 게임 시스템을 이용하면 각 플랫폼 별로 최적의 장소에 세이브 파일이 저장되며
에디터에서 저장하는 경우 프로젝트 파일의 Saved 폴더 안에 SaveGames 라는 폴더가 생성되고 여기에 저장된다
SaveGame 클래스를 상속받는 ABSaveGame 클래스를 생성해준다
ABSaveGame.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "ArenaBattle.h"
#include "GameFramework/SaveGame.h"
#include "ABSaveGame.generated.h"
/**
*
*/
UCLASS()
class ARENABATTLE_API UABSaveGame : public USaveGame
{
GENERATED_BODY()
public:
UABSaveGame();
UPROPERTY()
int32 Level;
UPROPERTY()
int32 Exp;
UPROPERTY()
FString PlayerName;
UPROPERTY()
int32 HighScore;
};
ABSaveGame.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "ABSaveGame.h"
UABSaveGame::UABSaveGame()
{
Level = 1;
Exp = 0;
PlayerName = TEXT("Guest");
HighScore = 0;
}
세이브 기능에는 각 저장 파일에 접근할 수 있는 고유 이름인 슬롯 이름이 필요하다
슬롯이름을 선언해주고, 세이브 파일이 없는 처음에는 세이브 파일을 생성하도록 InitPlayerData
에 구현하자
ABPlayerState.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "ArenaBattle.h"
#include "GameFramework/PlayerState.h"
#include "ABPlayerState.generated.h"
DECLARE_MULTICAST_DELEGATE(FOnPlayerStateChangedDelegate);
/**
*
*/
UCLASS()
class ARENABATTLE_API AABPlayerState : public APlayerState
{
GENERATED_BODY()
public:
AABPlayerState();
int32 GetGameScore() const;
int32 GetGameHighScore() const;
int32 GetCharacterLevel() const;
float GetExpRatio() const;
bool AddExp(int32 IncomeExp);
void AddGameScore();
void InitPlayerData();
void SavePlayerData();
FString SaveSlotName;
FOnPlayerStateChangedDelegate OnPlayerStateChanged;
protected:
UPROPERTY(Transient)
int32 GameHighScore;
...
};
ABPlayerState.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "ABPlayerState.h"
#include "ABGameInstance.h"
#include "ABSaveGame.h"
AABPlayerState::AABPlayerState()
{
CharacterLevel = 1;
GameScore = 0;
GameHighScore = 0;
Exp = 0;
SaveSlotName = TEXT("Player1");
}
...
int32 AABPlayerState::GetGameHighScore() const
{
return GameHighScore;
}
...
void AABPlayerState::InitPlayerData()
{
auto ABSaveGame = Cast<UABSaveGame>(UGameplayStatics::LoadGameFromSlot(SaveSlotName, 0));
if (nullptr == ABSaveGame)
ABSaveGame = GetMutableDefault<UABSaveGame>();
SetPlayerName(ABSaveGame->PlayerName);
SetCharacterLevel(ABSaveGame->Level);
GameScore = 0;
GameHighScore = ABSaveGame->HighScore;
Exp = ABSaveGame->Exp;
SavePlayerData();
}
...
bool AABPlayerState::AddExp(int32 IncomeExp)
{
...
OnPlayerStateChanged.Broadcast();
SavePlayerData();
return DidLevelUp;
}
void AABPlayerState::AddGameScore()
{
...
SavePlayerData();
}
...
void AABPlayerState::SavePlayerData()
{
UABSaveGame* NewPlayerData = NewObject<UABSaveGame>();
NewPlayerData->PlayerName = GetPlayerName();
NewPlayerData->Level = CharacterLevel;
NewPlayerData->Exp = Exp;
NewPlayerData->HighScore = GameHighScore;
UGameplayStatics::SaveGameToSlot(NewPlayerData, SaveSlotName, 0);
}
마지막으로 하이스코어 값을 HUD UI에 연동해준다
ABHUDWidget.cpp
void UABHUDWidget::UpdatePlayerState()
{
ExpBar ->SetPercent(CurrentPlayerState->GetExpRatio());
PlayerName ->SetText(FText::FromString(CurrentPlayerState->GetPlayerName()));
PlayerLevel ->SetText(FText::FromString(FString::FromInt(CurrentPlayerState->GetCharacterLevel())));
CurrentScore->SetText(FText::FromString(FString::FromInt(CurrentPlayerState->GetGameScore())));
HighScore ->SetText(FText::FromString(FString::FromInt(CurrentPlayerState->GetGameHighScore())));
}
결과를 확인해보자
게임을 종료하고 실행해도 레벨과 최고점이 남아있으며
세이브 파일 또한 제대로 생성되는것을 확인할 수 있다