* 플레이어의 데이터를 저장하고 이를 불러들이는 로직을 구현한다
* 언리얼 엔진은 게임의 데이터를 저장하고 불러들이는 기능을 제공한다. 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에 파일이 생성된다.
'Unreal > Game 1 (C++)' 카테고리의 다른 글
22. 게임의 완성 3 (타이틀 화면의 제작 ) (0) | 2019.05.12 |
---|---|
22. 게임의 완성 2 (전투 시스템의 설계) (0) | 2019.05.10 |
21. 게임플레이 제작 3 (게임 데이터의 관리) (0) | 2019.05.09 |
21. 게임플레이 제작 2 (플레이어 데이터와 UI 연동) (0) | 2019.05.08 |
21. 게임플레이 제작 1 (캐릭터 스테이트) (0) | 2019.05.08 |