사용자 설정과 환경 저장
UGameUserSettings를 확장해 그래픽·오디오·키 바인딩 같은 사용자 옵션을 저장하고 적용합니다.
이전 절들에서는 SaveGame 시스템과 일반 파일 입출력 및 JSON 처리를 통해 게임 데이터를 저장하고 관리하는 방법을 알아보았습니다.
이제 게임에서 매우 중요한 또 다른 종류의 데이터인 사용자 설정(User Settings)과 환경 설정(Environment Settings)을 저장하고 관리하는 방법에 대해 살펴보겠습니다.
여기에는 그래픽 품질, 오디오 볼륨, 키 바인딩, 언어 설정 등 플레이어가 게임 경험을 개인화할 수 있는 모든 옵션이 포함됩니다.
언리얼 엔진은 이를 위해 특별히 고안된 UGameUserSettings 클래스를 제공합니다.
이전 절들에서는 SaveGame 시스템과 일반 파일 입출력 및 JSON 처리를 통해 SaveGame으로 플레이 데이터를 저장했다면, 사용자 설정(User Settings)과 환경 설정(Environment Settings)은 해상도, 품질, 오디오 같은 실행 환경 값을 별도 경로에 보관해야 합니다.
- ApplySettings와 SaveSettings 적용 순서
UGameUserSettings는 플레이어별 설정을 저장하고 적용합니다. 2 UGameUserSettings를 상속해 프로젝트 설정 변수를 추가합니다. 3 프로젝트에서 UMyGameUserSettings를 사용하도록 엔진에 알려야 합니다. 4 해상도와 품질 값을 바꾼 뒤 적용과 저장을 같은 흐름으로 둡니다.
- UGameUserSettings 개념
UGameUserSettings는 플레이어별 설정을 저장하고 적용합니다.
- 커스텀 UGameUserSettings 클래스 생성
UGameUserSettings를 상속해 프로젝트 설정 변수를 추가합니다.
- 프로젝트 설정
프로젝트에서 UMyGameUserSettings를 사용하도록 엔진에 알려야 합니다.
- 사용자 설정 활용 및 적용
해상도와 품질 값을 바꾼 뒤 적용과 저장을 같은 흐름으로 둡니다.
- 사용자 설정 유지 검수
사용자 설정은 해상도, 음량, 입력 감도를 시작 시 적용합니다. 환경 설정은 기본값을 정하고 다음 실행까지 유지합니다. 언리얼 엔진은 이를 위해 UGameUserSettings 클래스를 사용합니다.
UGameUserSettings 시스템이란?
UGameUserSettings는 플레이어별 게임 설정을 영구적으로 저장하고 로드하며 적용하는 데 사용되는 언리얼 엔진의 내장 시스템입니다.
이 시스템은 각 플레이어의 디바이스에 독립적인 .ini 파일 형태로 설정 데이터를 저장합니다.
UGameUserSettings의 주요 특징
- 자동 저장/로드: 대부분의 기본 설정(해상도, 그래픽 품질 등)은 엔진에 의해 자동으로 처리됩니다.
- 플랫폼 독립적: SaveGame 시스템과 마찬가지로, 다양한 플랫폼에서 일관된 방식으로 설정이 관리됩니다.
- 쉬운 접근:
UGameplayStatics::GetGameUserSettings()함수를 통해 언제든지 현재 플레이어의 설정에 접근할 수 있습니다. - 확장성: 기본 설정을 넘어 게임 고유의 커스텀 설정을 추가하고 관리할 수 있습니다.
- 설정 적용: 변경된 설정을 게임에 즉시 적용하거나, 변경 사항을 임시로 저장했다가 나중에 일괄 적용할 수 있습니다.
커스텀 UGameUserSettings 클래스 생성
값을 저장하는 코드와 실제 게임 상태에 반영하는 코드를 나눠야 옵션이 안정적으로 유지된다.
| 단계 | 역할 | 확인 기준 |
|---|---|---|
| Config Variable | 볼륨, 언어, 해상도 같은 사용자 값을 선언한다 | UPROPERTY Config로 보관된다 |
| Getter / Setter | 읽기와 변경 경로를 명확히 둔다 | 검증 없이 아무 곳에서나 값을 바꾸지 않는다 |
| Load / Save | 시작 시 ini 값을 가져오고 변경값을 기록한다 | 저장 위치와 호출 시점이 맞다 |
| Apply | 해상도나 품질 설정을 실제 게임에 반영한다 | 파일 값과 런타임 상태가 따로 놀지 않는다 |
대부분의 프로젝트에서는 기본 UGameUserSettings 클래스를 직접 사용하는 대신, 이를 상속받아 게임 고유의 설정 변수를 추가합니다.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/GameUserSettings.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 bCheckFor===r= ===ssues) override;
};#include "MyGameUserSettings.h"
#include "Kismet/GameplayStatics.h"
#include "AudioDevice.h" // 오디오 볼륨 제어를 위해 포함 (선택 사항)
#include "GameFramework/PlayerController.h" // 플레이어 컨트롤러 접근을 위해 (선택 사항)
#include "Components/AudioComponent.h" // 사운드 컴포넌트 제어 (선택 사항)
UMyGameUserSettings::UMyGameUserSettings()
{
// 기본값 설정
MasterVolume = 0.75f;
bShowPlayerHealthBar = true;
PlayerPreferredLanguage = TEXT("en"); // 기본 언어 영어
CustomAbilityKeyBinds.Add(EKeys::Q); // 기본 Q 키 바인딩
CustomAbilityKeyBinds.Add(EKeys::E); // 기본 E 키 바인딩
}
UMyGameUserSettings* UMyGameUserSettings::GetMyGameUserSettings()
{
// UGameplayStatics::GetGameUserSettings()는 항상 유효한 UGameUserSettings 인스턴스를 반환
return Cast<UMyGameUserSettings>(UGameplayStatics::GetGameUserSettings());
}
void UMyGameUserSettings::SetMasterVolume(float NewVolume)
{
MasterVolume = FMath::Clamp(NewVolume, 0.0f, 1.0f);
// 변경 사항을 즉시 적용하고 싶다면 ApplySettings() 호출
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;
// 언어 변경은 엔진의 로컬라이제이션 시스템을 통해 적용
// FInternationalization::Get().SetCurrentCulture(NewLanguage); // 언어 변경
// UGameplayStatics::SetCurrentCulture(NewLanguage); // Kismet 버전을 사용하면 더 편리
ApplySettings(false); // 변경 사항 적용
}
FString UMyGameUserSettings::GetPlayerPreferredLanguage() const
{
return PlayerPreferredLanguage;
}
void UMyGameUserSettings::SaveSettings()
{
Super::SaveSettings(); // 부모 클래스의 SaveSettings 호출 (실제 파일 저장)
UE_LOG(LogTemp, Warning, TEXT("MyGameUserSettings: Settings Saved!"));
}
void UMyGameUserSettings::LoadSettings(bool bForceReload)
{
Super::LoadSettings(bForceReload); // 부모 클래스의 LoadSettings 호출
UE_LOG(LogTemp, Warning, TEXT("MyGameUserSettings: Settings Loaded!"));
// 로드된 후 필요에 따라 추가 초기화/유효성 검사 로직
MasterVolume = FMath::Clamp(MasterVolume, 0.0f, 1.0f);
}
void UMyGameUserSettings::ApplySettings(bool bCheckFor=ssues)
{
// 먼저 부모 클래스의 ApplySettings를 호출하여 기본 그래픽 설정 등을 적용
Super::ApplySettings(bCheckFor===r= ===ssues);
UE_LOG(LogTemp, Warning, TEXT("MyGameUserSettings: Settings Applied!"));
//========================================
// 커스텀 설정 적용 로직
//========================================
// 마스터 볼륨 적용 (예시)
// 모든 사운드 클래스에 대한 볼륨 설정은 Audio Mixer 또는 Sound Class Mixer를 통해 관리하는 것이 일반적입니다.
// 여기서는 간단히 Audio Device를 통해 모든 사운드에 영향을 줄 수 있는 방법을 예시로 듭니다.
FAudioDevice* AudioDevice = GEngine->GetMainAudioDevice();
if (AudioDevice)
{
// Audio Device의 Listener Volume 또는 특정 Sound Class의 Volume을 조절
// AudioDevice->SetMasterVolume(MasterVolume); // 이런 직접적인 함수는 일반적으로 사용되지 않음
// 대신, Audio Mixer에 커스텀 마스터 볼륨 Sound Class를 만들고 그 볼륨을 제어하는 방식이 더 일반적
}
// 또는 특정 AudioComponent의 볼륨을 직접 제어
// (이 방법은 모든 사운드에 적용되지 않으므로, 더 높은 수준의 오디오 시스템이 필요)
// 예를 들어, 월드의 모든 Ambient Sound Actor의 볼륨을 조절해야 할 수도 있습니다.
// 언어 설정 적용
FInternationalization::Get().SetCurrentCulture(PlayerPreferredLanguage);
// 키 바인딩 적용 (입력 시스템에 바인딩 로직 필요)
// Project Settings -> Input -> Action Mappings 또는 Axis Mappings을 C++에서 동적으로 변경하는 것은 복잡합니다.
// 보통은 FInputBindings와 같은 커스텀 시스템을 구축합니다.
// 이외의 게임 관련 설정 (예: HUD 체력 바 표시 여부)
// 이 설정은 주로 HUD 위젯에서 GetShowPlayerHealthBar()를 호출하여 조건부로 표시 여부를 결정합니다.
}사용자 설정은 값 변경, 적용, 저장, 되돌리기가 서로 다른 시점에 일어나므로 UI 흐름에서 상태를 나눠 관리해야 합니다.
옵션 화면의 값은 즉시 저장되는 값과 미리보기 값이 다릅니다. 임시 변경, 적용, 저장, 되돌리기를 나눠야 사용자가 결과를 예측하기 쉬워집니다.
- 설정 파일
ini Config 변수 커스텀 설정은 UPROPERTY(Config)로 저장 대상임을 드러냅니다. 플랫폼 경로 저장 위치는 플랫폼별 Saved/Config 아래로 분리됩니다.
- 상태 전환
적용 흐름 Loaded 시작 시 파일에서 읽은 현재 적용 값을 화면에 채웁니다. Draft 슬라이더나 토글 변경은 임시 값으로 먼저 보관합니다. Apply 해상도, 볼륨, 언어를 실제 시스템에 적용합니다. Save 확정된 값을 SaveSettings로 ini 파일에 기록합니다. Revert 취소하면 로드된 값으로 UI와 런타임을 되돌립니다.
- 옵션 적용 안전장치
guard 범위 보정 볼륨, 감도, 밝기 값은 Clamp 후 적용해야 합니다. 위험 변경 해상도와 전체 화면은 확인 타이머를 두어 자동 복구할 수 있게 합니다. UI 갱신 설정 적용 후 HUD와 메뉴가 새 값을 읽도록 이벤트를 보냅니다.
프로젝트 설정
프로젝트에서 UMyGameUserSettings를 사용하도록 엔진에 알려야 합니다.
이는 DefaultGameUserSettings.ini 파일에서 설정합니다.
Config/DefaultGameUserSettings.ini 파일을 엽니다. (없다면 프로젝트 루트의 Config 폴더에 생성)
다음 내용을 추가하거나 수정합니다.
[/Script/Engine.GameUserSettings]
GameUserSettingsClassName=/Script/MYPROJECT.MyGameUserSettingsMYPROJECT는 여러분의 프로젝트 모듈 이름입니다.
이렇게 설정하면 엔진은 게임 시작 시 UMyGameUserSettings의 인스턴스를 자동으로 생성하고 로드/저장 로직을 관리합니다.
사용자 설정 활용 및 적용
해상도와 전체화면 변경은 바로 저장하면 위험하다. 적용, 확인, 되돌리기, 저장 시점을 나눠야 UX가 안정된다.
- 1값 선택
UI에서 해상도, 전체화면, 품질 옵션을 임시 값으로 바꾼다. pending
- 2적용 호출
ApplySettings 또는 ApplyResolutionSettings로 화면에 먼저 반영한다. preview
- 3확인 대기
사용자가 화면을 볼 수 있는지 제한 시간 안에 확인한다. confirm
- 4저장
확인되면 SaveSettings로 설정 파일에 기록한다. persist
- 5되돌리기
확인하지 않거나 문제가 있으면 이전 값으로 Revert한다. rollback
C++에서 접근 및 변경
#include "MyGameUserSettings.h"
void AMyPlayerController::SetGameVolume(float NewVolume)
{
UMyGameUserSettings* UserSettings = UMyGameUserSettings::GetMyGameUserSettings();
if (UserSettings)
{
UserSettings->SetMasterVolume(NewVolume);
// SaveSettings()는 SetMasterVolume 내부에서 호출될 수도 있고,
// 옵션 메뉴에서 '적용' 버튼 클릭 시 일괄적으로 호출될 수도 있습니다.
UserSettings->SaveSettings();
}
}블루프린트에서 접근 및 변경
Get My Game User Settings 노드를 사용하여 인스턴스를 얻은 후, 공개된 함수(BlueprintCallable, BlueprintPure)를 호출하여 설정을 읽거나 변경할 수 있습니다.
Save Settings 및 Apply Settings 노드를 사용하여 변경 사항을 저장하고 적용합니다.
이미지 출처: Unreal Engine Documentation (Save Game Settings with UMG)
설정 파일 위치
UGameUserSettings는 기본적으로 다음 위치에 설정을 저장합니다.
- Windows:
C:\Users\[사용자명]\AppData\Local\[프로젝트명]\Saved\Config\Windows\GameUserSettings.ini - Android/iOS: 각 플랫폼의 앱 데이터 디렉토리 내에 저장됩니다.
이 파일은 일반 텍스트 .ini 형식으로 되어 있어 직접 열어볼 수 있으며, Config 매크로를 사용한 변수들이 섹션 형태로 저장됩니다.
; GameUserSettings.ini 예시
[GameSettings]
MasterVolume=0.650000
bShowPlayerHealthBar=True
PlayerPreferredLanguage=ko
CustomAbilityKeyBinds=(Keys=((KeyName="Q",IsGamepadKey=False,IsMouseButton=False,IsAction=False,IsAxis=False,IsDeprecated=False,IsModifierKey=False,IsReadyForBind=False,IsBindableInSettings=False,IsCustomInput=False),(KeyName="E",IsGamepadKey=False,IsMouseButton=False,IsAction=False,IsAxis=False,IsDeprecated=False,IsModifierKey=False,IsReadyForBind=False,IsBindableInSettings=False,IsCustomInput=False)))UGameUserSettings 시스템은 언리얼 엔진에서 사용자 설정과 환경을 효율적으로 관리하기 위한 표준적이고 강력한 방법입니다.
커스텀 클래스를 정의하고 Config 매크로를 사용하여 변수를 .ini 파일에 직렬화하며, SaveSettings() 및 ApplySettings() 함수를 통해 설정을 저장하고 게임에 적용하는 방법을 익히면 플레이어에게 개인화된 게임 경험을 제공할 수 있습니다.
이는 게임의 접근성을 높이고 플레이어 만족도를 향상시키는 데 필수적인 요소입니다.
이것으로 7장 저장 및 데이터 관리를 마칩니다.
사용자 설정은 값을 바꾸는 순간, 실제 게임에 적용하는 순간, 디스크에 저장하는 순간을 분리해 설계해야 합니다.
`UGameUserSettings`를 확장하면 그래픽, 사운드, 언어, 키 바인딩을 플레이어별 `.ini` 흐름으로 일관되게 다룰 수 있습니다.
- LoadSettings
읽기 저장된 `.ini` 값을 불러오고 범위를 벗어난 값은 기본값으로 보정합니다.
- Setter 호출
변경 볼륨, 언어, 표시 옵션은 전용 함수에서 Clamp와 검증을 통과시킵니다.
- ApplySettings
적용 해상도, 품질, 오디오 같은 변경을 현재 세션에 반영합니다.
- SaveSettings
저장 확정된 값만 디스크에 저장해 다음 실행에서도 같은 설정을 유지합니다.
- 커스텀 설정에서 확인할 항목
저장 대상 변수는 Config 속성으로 선언해 엔진 설정 파일 흐름에 태웁니다. 생성자와 로드 직후에 안전한 기본값과 허용 범위를 다시 확인합니다. 언어와 HUD 옵션은 위젯이나 매니저가 변경 신호를 받아 갱신해야 합니다.
- UPROPERTY(Config)
저장 대상 변수는 Config 속성으로 선언해 엔진 설정 파일 흐름에 태웁니다.
- 기본값
생성자와 로드 직후에 안전한 기본값과 허용 범위를 다시 확인합니다.
- UI 반영
언어와 HUD 옵션은 위젯이나 매니저가 변경 신호를 받아 갱신해야 합니다.
사용자 설정은 옵션 UI, 런타임 시스템, 저장 파일이 서로 다른 책임을 갖도록 나눌 때 되돌리기와 검증이 쉬워집니다.
사용자 설정은 값 변경, 미리보기, 적용, 저장, 되돌리기가 각자 다른 시점에 일어나므로 단계별 검증 기준을 갖춰야 합니다.
- 임시 값 편집
UI 슬라이더와 토글은 바로 저장하지 않고 화면에 보이는 후보 값으로 보관합니다.
- 범위와 충돌 확인
범위 충돌 볼륨 범위, 지원 해상도, 중복 키 입력처럼 실패 가능한 조건을 먼저 걸러냅니다.
- 세션에 반영
적용 ApplySettings 이후 UI와 실제 게임 상태가 같은 값을 보고 있는지 확인합니다.
- 확정 값 기록
저장 확인 버튼을 누른 값만 SaveSettings로 기록하고 재시작 후 유지되는지 봅니다.
- 테스트해야 할 세 가지 경계
지원하지 않는 해상도나 음수 볼륨이 들어와도 안전한 기본값으로 보정합니다. 적용 전 취소, 적용 후 되돌림, 창 닫기 같은 중단 경로를 모두 확인합니다. 저장된 값이 다음 실행에서 로드되고 위젯 초기값과 일치하는지 비교합니다.
- 잘못된 입력
지원하지 않는 해상도나 음수 볼륨이 들어와도 안전한 기본값으로 보정합니다.
- 취소 흐름
적용 전 취소, 적용 후 되돌림, 창 닫기 같은 중단 경로를 모두 확인합니다.
- 재시작
저장된 값이 다음 실행에서 로드되고 위젯 초기값과 일치하는지 비교합니다.