사용자 설정과 환경 저장
UGameUserSettings를 확장해 그래픽·오디오·키 바인딩 같은 사용자 옵션을 저장하고 적용합니다.
이전 절들에서는 SaveGame 시스템과 일반 파일 입출력 및 JSON 처리를 통해 게임 데이터를 저장하고 관리하는 방법을 알아보았습니다.
이제 게임에서 매우 중요한 또 다른 종류의 데이터인 사용자 설정(User Settings)과 환경 설정(Environment Settings)을 저장하고 관리하는 방법에 대해 살펴보겠습니다.
여기에는 그래픽 품질, 오디오 볼륨, 키 바인딩, 언어 설정 등 플레이어가 게임 경험을 개인화할 수 있는 모든 옵션이 포함됩니다.
언리얼 엔진은 이를 위해 특별히 고안된 UGameUserSettings 클래스를 제공합니다.
UGameUserSettings 시스템이란?
UGameUserSettings는 현재 로컬 기기의 게임 설정을 저장·로드·적용하는 시스템입니다. 계정별 또는 분할 화면 플레이어별 프로필을 자동으로 나누지는 않습니다.
이 시스템은 각 플레이어의 디바이스에 독립적인 .ini 파일 형태로 설정 데이터를 저장합니다.
UGameUserSettings의 주요 특징
- 자동 저장/로드: 대부분의 기본 설정(해상도, 그래픽 품질 등)은 엔진에 의해 자동으로 처리됩니다.
- 플랫폼 독립적: SaveGame 시스템과 마찬가지로, 다양한 플랫폼에서 일관된 방식으로 설정이 관리됩니다.
- 접근: 정적 함수
UGameUserSettings::GetGameUserSettings()로 로컬 설정 객체를 얻습니다. 커스텀 타입으로 캐스팅한 결과는 검사해야 합니다. - 확장성: 기본 설정을 넘어 게임 고유의 커스텀 설정을 추가하고 관리할 수 있습니다.
- 설정 적용: 변경된 설정을 게임에 즉시 적용하거나, 변경 사항을 임시로 저장했다가 나중에 일괄 적용할 수 있습니다.
커스텀 UGameUserSettings 클래스 생성
대부분의 프로젝트에서는 기본 UGameUserSettings 클래스를 직접 사용하는 대신, 이를 상속받아 게임 고유의 설정 변수를 추가합니다.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/GameUserSettings.h"
#include "InputCoreTypes.h"
#include "MyGameUserSettings.generated.h"
UCLASS()
class MYPROJECT_API UMyGameUserSettings : public UGameUserSettings
{
GENERATED_BODY()
public:
UMyGameUserSettings();
// 싱글톤 패턴처럼 어디서든 쉽게 접근할 수 있는 헬퍼 함수
UFUNCTION(BlueprintCallable, Category = "Game Settings")
static UMyGameUserSettings* GetMyGameUserSettings();
//========================================
// 커스텀 게임 설정 변수들
// UPROPERTY로 선언해야 직렬화 대상이 됩니다.
//========================================
UPROPERTY(Config) // .ini 파일에 저장될 수 있도록 Config 지정
float MasterVolume;
UPROPERTY(Config)
bool bShowPlayerHealthBar;
UPROPERTY(Config)
FString PlayerPreferredLanguage;
UPROPERTY(Config)
TArray<FKey> CustomAbilityKeyBinds; // 커스텀 능력 키 바인딩 (예시)
//========================================
// 커스텀 설정 제어 함수들
//========================================
UFUNCTION(BlueprintCallable, Category = "Game Settings")
void SetMasterVolume(float NewVolume);
UFUNCTION(BlueprintPure, Category = "Game Settings")
float GetMasterVolume() const;
UFUNCTION(BlueprintCallable, Category = "Game Settings")
void SetShowPlayerHealthBar(bool bShow);
UFUNCTION(BlueprintPure, Category = "Game Settings")
bool GetShowPlayerHealthBar() const;
UFUNCTION(BlueprintCallable, Category = "Game Settings")
void SetPlayerPreferredLanguage(const FString& NewLanguage);
UFUNCTION(BlueprintPure, Category = "Game Settings")
FString GetPlayerPreferredLanguage() const;
// 변경 사항을 .ini 파일에 저장 (부모 클래스 함수 오버라이드)
virtual void SaveSettings() override;
// 저장된 설정을 로드하거나 기본값을 적용 (부모 클래스 함수 오버라이드)
virtual void LoadSettings(bool bForceReload = false) override;
// 설정을 게임에 적용 (그래픽, 사운드 등)
virtual void ApplySettings(bool bCheckForCommandLineOverrides) override;
};#include "MyGameUserSettings.h"
#include "Internationalization/Internationalization.h"
UMyGameUserSettings::UMyGameUserSettings()
{
// 기본값 설정
MasterVolume = 0.75f;
bShowPlayerHealthBar = true;
PlayerPreferredLanguage = TEXT("en"); // 기본 언어 영어
CustomAbilityKeyBinds.Add(EKeys::Q); // 기본 Q 키 바인딩
CustomAbilityKeyBinds.Add(EKeys::E); // 기본 E 키 바인딩
}
UMyGameUserSettings* UMyGameUserSettings::GetMyGameUserSettings()
{
// 엔진 설정 클래스 등록과 초기화 상태에 따라 캐스팅은 실패할 수 있습니다.
return Cast<UMyGameUserSettings>(UGameUserSettings::GetGameUserSettings());
}
void UMyGameUserSettings::SetMasterVolume(float NewVolume)
{
MasterVolume = FMath::Clamp(NewVolume, 0.0f, 1.0f);
// 값만 변경합니다. 옵션 UI의 적용 버튼에서 ApplySettings(false)를 호출합니다.
}
float UMyGameUserSettings::GetMasterVolume() const
{
return MasterVolume;
}
void UMyGameUserSettings::SetShowPlayerHealthBar(bool bShow)
{
bShowPlayerHealthBar = bShow;
// UI 관련 설정은 주로 UI 위젯에서 직접 이 변수를 참조하여 처리합니다.
// 즉시 UI 업데이트를 강제하려면 UI 관리자에게 알림을 보내야 합니다.
}
bool UMyGameUserSettings::GetShowPlayerHealthBar() const
{
return bShowPlayerHealthBar;
}
void UMyGameUserSettings::SetPlayerPreferredLanguage(const FString& NewLanguage)
{
PlayerPreferredLanguage = NewLanguage;
// 값만 변경합니다. 실제 문화권 변경은 ApplySettings에서 시도합니다.
}
FString UMyGameUserSettings::GetPlayerPreferredLanguage() const
{
return PlayerPreferredLanguage;
}
void UMyGameUserSettings::SaveSettings()
{
Super::SaveSettings(); // 부모 클래스의 SaveSettings 호출 (실제 파일 저장)
UE_LOG(LogTemp, Warning, TEXT("MyGameUserSettings: SaveSettings returned."));
}
void UMyGameUserSettings::LoadSettings(bool bForceReload)
{
Super::LoadSettings(bForceReload); // 부모 클래스의 LoadSettings 호출
UE_LOG(LogTemp, Warning, TEXT("MyGameUserSettings: LoadSettings returned."));
// 로드된 후 필요에 따라 추가 초기화/유효성 검사 로직
MasterVolume = FMath::Clamp(MasterVolume, 0.0f, 1.0f);
}
void UMyGameUserSettings::ApplySettings(bool bCheckForCommandLineOverrides)
{
// 부모 구현은 기본 설정을 적용하고 SaveSettings도 호출합니다.
Super::ApplySettings(bCheckForCommandLineOverrides);
//========================================
// 커스텀 설정 적용 로직
//========================================
// 마스터 볼륨의 실제 오디오 적용은 미구현입니다.
// 프로젝트의 Sound Class/Mix 또는 오디오 제어 경로에 MasterVolume을 전달해야 합니다.
// 언어 설정 적용
if (!FInternationalization::Get().SetCurrentCulture(PlayerPreferredLanguage))
{
UE_LOG(LogTemp, Warning, TEXT("Culture was not applied: %s"), *PlayerPreferredLanguage);
}
// 키 바인딩 적용 (입력 시스템에 바인딩 로직 필요)
// Project Settings -> Input -> Action Mappings 또는 Axis Mappings을 C++에서 동적으로 변경하는 것은 복잡합니다.
// 보통은 FInputBindings와 같은 커스텀 시스템을 구축합니다.
// 이외의 게임 관련 설정 (예: HUD 체력 바 표시 여부)
// 이 설정은 주로 HUD 위젯에서 GetShowPlayerHealthBar()를 호출하여 조건부로 표시 여부를 결정합니다.
}이 예제의 setter는 메모리 값만 바꿉니다. 적용 버튼은 ApplySettings(false)를 호출하며 부모 구현의 저장도 함께 실행됩니다. 취소 UI를 만들려면 편집 전 값을 별도로 보관·복원해야 합니다. RevertVideoMode는 해상도와 전체 화면 모드용이며 커스텀 음량·언어 취소를 대신하지 않습니다.
프로젝트 설정
프로젝트에서 UMyGameUserSettings를 사용하도록 엔진에 알려야 합니다.
이는 DefaultEngine.ini 파일에서 설정합니다.
Config/DefaultEngine.ini 파일을 엽니다. (없다면 프로젝트 루트의 Config 폴더에 생성)
다음 내용을 추가하거나 수정합니다.
[/Script/Engine.Engine]
GameUserSettingsClassName=/Script/MYPROJECT.MyGameUserSettingsMYPROJECT는 여러분의 프로젝트 모듈 이름입니다.
이렇게 설정하면 엔진은 게임 시작 시 UMyGameUserSettings의 인스턴스를 자동으로 생성하고 로드/저장 로직을 관리합니다.
사용자 설정 활용 및 적용
C++에서 접근 및 변경
AMyPlayerController 헤더에 SetGameVolume을 선언한 부분 예제입니다. 버튼의 실제 적용 호출은 UI에서 연결해야 합니다.
#include "MyPlayerController.h"
#include "MyGameUserSettings.h"
void AMyPlayerController::SetGameVolume(float NewVolume)
{
UMyGameUserSettings* UserSettings = UMyGameUserSettings::GetMyGameUserSettings();
if (UserSettings)
{
UserSettings->SetMasterVolume(NewVolume);
// 여기서는 편집 값만 변경합니다.
// 옵션 메뉴의 적용 버튼: UserSettings->ApplySettings(false);
}
}블루프린트에서 접근 및 변경
Get My Game User Settings 노드를 사용하여 인스턴스를 얻은 후, 공개된 함수(BlueprintCallable, BlueprintPure)를 호출하여 설정을 읽거나 변경할 수 있습니다.
Apply Settings는 기본 설정 적용과 저장을 포함합니다. Save Settings만 호출하면 커스텀 런타임 적용을 대신하지 않습니다.
설정 파일 위치
UGameUserSettings는 기본적으로 다음 위치에 설정을 저장합니다.
- Windows 패키지 예시:
C:\Users\[사용자명]\AppData\Local\[프로젝트명]\Saved\Config\Windows\GameUserSettings.ini. 에디터와 빌드 대상에 따라 디렉터리가 달라집니다. - Android/iOS: 각 플랫폼의 앱 데이터 디렉토리 내에 저장됩니다.
이 파일은 일반 텍스트 .ini 형식으로 되어 있어 직접 열어볼 수 있으며, Config 매크로를 사용한 변수들이 섹션 형태로 저장됩니다.
; GameUserSettings.ini의 커스텀 속성 일부를 나타낸 형식 예시
[/Script/MYPROJECT.MyGameUserSettings]
MasterVolume=0.650000
bShowPlayerHealthBar=True
PlayerPreferredLanguage=ko커스텀 Config 속성의 저장과 기능 적용은 구별합니다.
| 호출·값 | 현재 구현 | 구별할 점 |
|---|---|---|
| LoadSettings | 부모에서 설정을 읽고 MasterVolume 범위를 보정합니다. | 읽기만으로 이 예제의 커스텀 오디오·언어 적용이 실행되지는 않습니다. |
| ApplySettings | 부모의 기본 설정 적용·저장 뒤 문화권 변경을 시도합니다. | 문화권 적용 실패를 기록하지만 앞선 저장을 되돌리지는 않습니다. 유효한 문화권·리소스 정책은 별도입니다. |
| 음량·체력 바 | 음량 값과 표시 플래그를 보관합니다. | 오디오 제어와 HUD 갱신은 구현하지 않았습니다. 값 변경만으로 해당 효과가 생기지 않습니다. |
| 키 배열 | Config 속성에 FKey 배열을 보관합니다. | 배열 저장은 런타임 입력 재바인딩이 아닙니다. 사용하는 입력 시스템에 별도 적용해야 합니다. |
- LoadSettings
- 현재 구현: 부모에서 설정을 읽고 MasterVolume 범위를 보정합니다.구별할 점: 읽기만으로 이 예제의 커스텀 오디오·언어 적용이 실행되지는 않습니다.
- ApplySettings
- 현재 구현: 부모의 기본 설정 적용·저장 뒤 문화권 변경을 시도합니다.구별할 점: 문화권 적용 실패를 기록하지만 앞선 저장을 되돌리지는 않습니다. 유효한 문화권·리소스 정책은 별도입니다.
- 음량·체력 바
- 현재 구현: 음량 값과 표시 플래그를 보관합니다.구별할 점: 오디오 제어와 HUD 갱신은 구현하지 않았습니다. 값 변경만으로 해당 효과가 생기지 않습니다.
- 키 배열
- 현재 구현: Config 속성에 FKey 배열을 보관합니다.구별할 점: 배열 저장은 런타임 입력 재바인딩이 아닙니다. 사용하는 입력 시스템에 별도 적용해야 합니다.
SaveSettings와 LoadSettings의 void 반환 뒤 로그는 호출 흐름 표시입니다. 저장 파일의 실제 내용이나 옵션 효과를 실행 검증한 결과가 아닙니다.
설정 파일은 사용자가 수정할 수 있으므로 로드 후 값 검증이 필요합니다. 이 예제는 음량 범위만 보정하며, 실제 오디오·입력 시스템과 UI 갱신 연결은 프로젝트에서 완성해야 합니다.