게임의 완성 (1) 세이브 파일 만들기

유영준·2023년 1월 29일

오늘은 게임의 중요한 기능인 세이브 파일을 구현하도록 하겠다

세이브 파일 클래스 구축

언리얼 엔진은 게임 데이터를 저장하고 불러들이는 기능을 가진 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())));
}

결과를 확인해보자

게임을 종료하고 실행해도 레벨과 최고점이 남아있으며

세이브 파일 또한 제대로 생성되는것을 확인할 수 있다

profile
토비폭스가 되고픈 게임 개발자

0개의 댓글