音量調整は AudioMixerの記事 で、解像度は 画面設定の記事 で、言語は Localizationの記事 で、 キーコンフィグは リバインドの記事 で——個別には全部できるようになった。ところが、いざ「設定画面」として1つにまとめると、別の敵が現れます。 保存キーがバラバラに散らばる。起動しても半分しか復元されない。スライダーは動くのに音が変わらない。
設定画面の難しさは個々の機能ではなく 統合 にあります。この記事では、設定を1つのデータ(SettingsData)に集め、適用役と保存役を分け、 起動時に全設定を復元する ところまでを完成させます。各分野の深掘りは上のリンク先に任せ、ここでは「一本につなぐ」ことだけに集中します。
この記事でわかること
- 設定画面が崩壊する典型パターン( 保存の散乱・復元漏れ )
- SettingsData に全設定を1本化する設計
- 音量(AudioMixer)・画面(Screen)・言語(Localization)・操作(Rebind)の 適用コード
- 保存はPlayerPrefsの1キー(JSON化)に集約する
- 実践:起動時に全設定を復元する SettingsManager
動作確認環境: Unity 2022.3 LTS / Unity 6・Input System・Localizationパッケージ
設定画面は「寄せ集め」ではなく1つのシステム
個別記事のコードをそのまま設定画面に貼り合わせると、こうなりがちです。
- 音量はスクリプトAが
PlayerPrefs.SetFloat("bgm")で保存 - 解像度はスクリプトBが
PlayerPrefs.SetInt("width")と"height"で保存 - 言語は自前キー
"lang"と公式Selectorで 二重管理 - キーコンフィグは……保存し忘れていた
その結果が「起動するたび音量だけ戻っている」「言語が再起動で食い違う」です。原因はシンプルで、 設定という1つの関心事が、コードのあちこちに散っている から。治療法もシンプルです—— 1カ所に集めます。

設計:データ1つ、適用役と保存役
設計は3つの部品でできています。

| 部品 | 役割 |
|---|---|
| SettingsData | 全設定の値を持つただのクラス(保存の単位) |
| Apply(適用) | 値をゲームへ反映する(Mixerへ、Screenへ、Localeへ…) |
| Save / Load(保存) | SettingsDataを丸ごと書く・読む |
分けて考えるのが肝心です。 「値を変える」と「ゲームに反映する」と「ディスクに残す」は別の仕事 で、スライダーを動かした瞬間はApplyだけ、決定した時にSave、起動した時にLoad+Apply——と組み合わせて使います。
// SettingsData.cs — 全設定の入れ物(ただのデータクラス)
[System.Serializable]
public class SettingsData
{
// 音量(0〜1)
public float masterVolume = 0.8f;
public float bgmVolume = 0.8f;
public float seVolume = 0.8f;
// 画面
public int resolutionWidth = 1920;
public int resolutionHeight = 1080;
public bool fullscreen = true;
// 操作(リバインドの上書き分JSON。空なら既定のまま)
public string bindingOverridesJson = "";
// 言語は公式Selectorに任せるため、ここには持たない(後述)
}
4分野の適用コード
それぞれの分野の「反映のしかた」は、既存記事で学んだ通りです。要点だけ集めます。
音量 → AudioMixer(詳細は AudioMixerの記事):
// スライダーの0〜1を、Mixerの対数dBへ変換して渡す
void ApplyVolume(string parameter, float value01)
{
float dB = Mathf.Log10(Mathf.Clamp(value01, 0.0001f, 1f)) * 20f;
audioMixer.SetFloat(parameter, dB); // "BGMVolume"などExposeしたパラメータ名
}
画面 → Screen(詳細は 画面設定の記事):
void ApplyDisplay(SettingsData data)
{
Screen.SetResolution(data.resolutionWidth, data.resolutionHeight, data.fullscreen);
}
言語 → Localization(詳細は Localizationの記事):
// SelectedLocaleを切り替えるだけ。保存と起動時復元は
// 公式のPlayerPrefs Selectorが担当するので、自前で保存しない(二重管理禁止)
void ApplyLanguage(Locale locale)
{
LocalizationSettings.SelectedLocale = locale;
}
操作 → Input System(詳細は リバインドの記事):
// 保存時: 上書き分だけをJSON文字列にする
data.bindingOverridesJson = inputActions.SaveBindingOverridesAsJson();
// 復元時: JSONを読み戻す(空文字なら何もしない=既定のキー配置)
if (!string.IsNullOrEmpty(data.bindingOverridesJson))
{
inputActions.LoadBindingOverridesFromJson(data.bindingOverridesJson);
}
保存:PlayerPrefsの1キーに集約する
保存先は PlayerPrefs で十分——ただしキーを散らかさず、 SettingsDataをJSONにして1キーへ 入れます。
const string SettingsKey = "game_settings";
void Save(SettingsData data)
{
string json = JsonUtility.ToJson(data);
PlayerPrefs.SetString(SettingsKey, json);
PlayerPrefs.Save();
}
SettingsData Load()
{
if (!PlayerPrefs.HasKey(SettingsKey))
{
return CreateDefaults(); // 初回起動:環境から初期値を作る(実践で後述)
}
return JsonUtility.FromJson<SettingsData>(PlayerPrefs.GetString(SettingsKey));
}
キーが1つなら「どこかの設定だけ保存し忘れる」事故が構造的に消えます。項目を増やすときもSettingsDataにフィールドを足すだけです。設定の構造を大きく変える日が来たら、セーブデータのバージョン管理 と同じ version フィールドの考え方がそのまま使えます。
実践:起動時に全設定を復元する
仕上げに、全部をつなぐ SettingsManager を作ります。仕事は3つ——起動時に Load→ApplyAll、UIから値が変わったら Apply、決定されたら Save です。

// SettingsManager.cs — 起動シーンに1つ置く
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.InputSystem;
public class SettingsManager : MonoBehaviour
{
[SerializeField] private AudioMixer audioMixer;
[SerializeField] private InputActionAsset inputActions;
public SettingsData Current { get; private set; }
const string SettingsKey = "game_settings";
void Awake()
{
// 起動時の入口はここ1カ所:読み込んで、全分野へ適用
Current = Load();
ApplyAll(Current);
}
public void ApplyAll(SettingsData data)
{
ApplyVolume("MasterVolume", data.masterVolume);
ApplyVolume("BGMVolume", data.bgmVolume);
ApplyVolume("SEVolume", data.seVolume);
Screen.SetResolution(data.resolutionWidth, data.resolutionHeight, data.fullscreen);
if (!string.IsNullOrEmpty(data.bindingOverridesJson))
{
inputActions.LoadBindingOverridesFromJson(data.bindingOverridesJson);
}
// 言語は公式Selectorが起動時に復元するので、ここでは触らない
}
// ---- UIのスライダー/トグルから呼ぶ(即時反映) ----
public void SetBgmVolume(float value01)
{
Current.bgmVolume = value01;
ApplyVolume("BGMVolume", value01);
}
// ---- 設定画面を閉じる/決定ボタンで呼ぶ ----
public void SaveCurrent()
{
Current.bindingOverridesJson = inputActions.SaveBindingOverridesAsJson();
PlayerPrefs.SetString(SettingsKey, JsonUtility.ToJson(Current));
PlayerPrefs.Save();
}
// ---- 初回起動:ユーザーの環境から初期値を作る ----
SettingsData CreateDefaults()
{
var data = new SettingsData
{
resolutionWidth = Screen.currentResolution.width,
resolutionHeight = Screen.currentResolution.height,
fullscreen = true
};
return data;
}
SettingsData Load()
{
if (!PlayerPrefs.HasKey(SettingsKey)) return CreateDefaults();
return JsonUtility.FromJson<SettingsData>(PlayerPrefs.GetString(SettingsKey));
}
void ApplyVolume(string parameter, float value01)
{
float dB = Mathf.Log10(Mathf.Clamp(value01, 0.0001f, 1f)) * 20f;
audioMixer.SetFloat(parameter, dB);
}
}
UI側の配線は素直です。スライダーの OnValueChanged に SetBgmVolume を( 動かした瞬間に音が変わる のが良い設定画面の条件です)、設定画面を閉じるボタンに SaveCurrent をつなぎます。
確認の儀式はこうです。BGMを小さくし、ウィンドウモードへ切り替え、キーを1つ変えて、設定画面を閉じる。 ゲームを完全に終了して、起動し直す。タイトルのBGMが小さいまま、ウィンドウのまま、変えたキーが効いたままなら——全経路がつながっています。もしどれか1つだけ戻っていたら、その分野の「Applyのし忘れ」(保存はされているのに反映していない)をまず疑ってください。設定バグの9割はSaveではなくApplyの漏れです。
ポイントは2つ。 起動時の入口は1カ所(Awake のLoad→ApplyAll。ここに全部通す)。 変更は即Apply、保存は区切りで(スライダーごとにPlayerPrefsへ書かない)。
おまけ:先に知っておくと良いこと
- 危険な設定には「元に戻す」猶予を: 解像度変更は、失敗すると画面が見えなくなって操作不能になり得ます。「この設定を保持しますか? 10秒後に元に戻ります」という確認ダイアログは、PCゲームの定番の保険です
- リセットボタンを最初から: 「デフォルトに戻す」は
ApplyAll(new SettingsData())+キーコンフィグのRemoveAllBindingOverrides()で作れます。設定をいじり壊したプレイヤーの救済路として、最初から用意しておく価値があります - グラフィック品質の段階: Quality Settings(Low/Medium/High)を項目 に足すのが次の一歩です。
QualitySettings.SetQualityLevel()で切り替えられ、SettingsDataにintを1つ足すだけで収まります
まとめ
- 設定画面の敵は個々の機能ではなく 統合。保存キーの散乱と復元漏れが二大事故
- SettingsData(データ)・Apply(反映)・Save/Load(保存) の3役に分ける
- 保存は PlayerPrefsの1キーにJSON で集約。言語だけは 公式Selectorに一本化 して自前保存しない
- 起動時の入口は
AwakeのLoad→ApplyAll の1カ所 - 検証は 完全再起動。1つだけ戻る症状は、SaveでなくApplyの漏れ
あなたのゲームをいま再起動したら、設定はいくつ生き残るでしょうか——4つ全部なら、この記事はもう卒業です。