* 플레이어의 데이터를 저장하고 이를 불러들이는 로직을 구현한다

* 언리얼 엔진은 게임의 데이터를 저장하고 불러들이는 기능을 제공한다. SaveGame이라는 언리얼 오브젝트를 상속받은 클래스를 설계하고 이를 언리얼이 제공하는 세이브게임 시스템에 넘겨주면 게임 데이터의 저장과 로딩을 간편하게 구현할 수 있다.

* 언리얼의 세이브게임 시스템을 사용하면 각 플랫폼별로 알맞은 최적의 장소에 데이터가 저장되며, 에디터에서 게임 데이터를 저장하는 ㄴ경우 프로젝트의 Saved 폴더에 있는 SaveGames라는 폴더에 게임데이터가 저장된다.

* SaveGame을 상속하여 클래스를 생성한다.

* 게임세이브 기능에는 각 저장 파일에 접근 \할 수 있는 고유 이름인 슬롯 이름이 필요하다. 슬롯 이름을 다르게 지정해 세이브 데이터를 여러 개 만들 수 있는데, 우리는 Player1이라는 슬롯 이름을 사용해 하나의 세이브 파일만 관리해본다. 처음에는 세이브된 게임 데이터가 없으므로 기본 세이트 데이터를 생성하는 로직을 플레이어 스테이트의 InitPlayerData에 구현된다. 

//ABSaveGame.h
#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
#include "ABSaveGame.h"

UABSaveGame::UABSaveGame()
{
	Level = 1;
	Exp = 0;
	PlayerName = TEXT("Guest");
	HighScore = 0;
}

//ABPlayerState.h
class ARENABATTLE_API AABPlayerState : public APlayerState
{


public:
	int32 GetGameHighScore() const;

protected:
	UPROPERTY(Transient)
	int32 GameHighScore;
}

//ABPlayerState.cpp
#include "ABSaveGame.h"

AABPlayerState::AABPlayerState()
{
	CharacterLevel = 1;
	GameScore = 0;
	Exp	= 0;

	GameHighScore = 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;
}

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

 

* 시작하면 UI에 초기화된 플레이어의 데이터가 나타난다.

초기화된 화면


* 이제 플레이어에 관련된 데이터가 변경될 때마다 이를 저장하도록 기능을 구현한다. 최초에 플레이어 데이터를 생성한 후 바로 저장하고, 이후 경험치에 변동이 있을 때마다 저장하는 로직은 다음과 같다

void AABPlayerState::InitPlayerData()
{
......
	SavePlayerData();
}

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

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

bool AABPlayerState::AddExp(int32 IncomeExp)
{
.....
	SavePlayerData();
	return DidLevelUp;
}

void AABPlayerState::AddGameScore()
{
......
	SavePlayerData();
}

 

* 언리얼 오브젝트를 생성할 때는 NewObject 명령을 사용하며, Newobject로 생성된 오브젝트를 더 이상 사용하지 않으면 언리얼 실행 환경의 가비지 컬렉터가 이를 탐지해 자동으로 언리얼 오브젝트를 소멸시킨다. 따라서 NewObject로 새성한 언리얼 오브젝트를 삭제하기 위해 delete 키워드를 사용하지 않아도 된다. 

* 월드에 액터를 생성하는 작업도 언리얼 오브젝트를 생성하는 작업이라고 할 수 있다. 하지만 액터는 생성할 떄 고려할 점들이 많으므로 언리얼 엔진은 이를 포괄한 SpawnActor라는 API를 제공하고 있다. SpawnActor의 로직 내부를 살펴보면 결국 newObject를 사용해 액터를 생성한다. 


* 이제 플레이어 스테이트의 하이스코어 값을 HUD UI에 연동시킨다.

//UABHUDWidget.cpp

void UABHUDWidget::UpdatePlayerState()
{
...........
  HighScore->SetText(FText::FromString(FString::FromInt(CurrentPlayerState->GetGameHighScore())));
};

 

* 이제 실행을 하면 SaveGames에 파일이 생성된다. 

 

 

+ Recent posts