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

유영준·2023년 1월 29일
0

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

세이브 파일 클래스 구축

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