🎮

【Unity】既存のSliderやToggleの状態を簡易的に保存する拡張メソッド【SaveStateExtensions】

に公開

はじめに

20190925-024041.png

設定画面など、スライダーやチェックボックス(Toggle)を扱うことがあります。多分ソースコードはこんな感じになっています。

ConfigController.cs
using UnityEngine;
using UnityEngine.UI;

namespace hoge
{
    public class ConfigController : MonoBehaviour
    {
        [SerializeField] Toggle BGMToggle, SEToggle, VoiceToggle;
        [SerializeField] Slider BGMSlider, SESlider, VoiceSlder;
        [SerializeField] InputField MemoInputField;
        [SerializeField] AudioSource BGMSource, SESource, VoiceSource;

        void Update()
        {
            // AudioSourceのミュート状態を制御
            BGMSource.mute = BGMToggle.isOn;
            SESource.mute = SEToggle.isOn;
            VoiceSource.mute = VoiceToggle.isOn;

            // AudioSourceの音量を制御
            BGMSource.volume = BGMSlider.value;
            SESource.volume = SESlider.value;
            VoiceSource.volume = VoiceSlder.value;
        }
    }
}

これらは多くの場合、アプリが終了しても保持しておく必要があると思うので、今回は拡張メソッドを使って実現してみました。

使い方

まずSaveStateExtensions.csをDLし、プロジェクト内にインポートします。

次に保存したいコンポーネントに対して、Start()内などで以下の様に呼び出してあげるだけです。

void Start()
{
    // Toggleの場合
    BGMToggle.SaveState("BGMToggle");
    SEToggle.SaveState("SEToggle");
    VoiceToggle.SaveState("VoiceToggle");

    // Sliderの場合
    BGMSlider.SaveState("BGMSlider");
    SESlider.SaveState("SESlider");
    VoiceSlder.SaveState("VoiceSlder");

    // InputFieldの場合
    MemoInputField.SaveState("MemoInputField");
}

引数のkeyだけは重複しないように気を付けて下さい。(nameof(BGMToggle)を渡してもいいかも)

アプローチ

ソースコード全文はこのようになっています。

Gits: SaveStateExtensions.cs

SaveStateExtensions.cs
using UnityEngine;
using UnityEngine.UI;

public static class SaveStateExtensions
{
    public static void SaveState(this Toggle toggle, string key)
    {
        key = $"{new System.Diagnostics.StackFrame(1).GetMethod().ReflectedType}+{key}";
        Debug.Log(key);
        toggle.isOn = PlayerPrefs.GetInt(key, 0) == 1;
        toggle.onValueChanged.AddListener(isOn => PlayerPrefs.SetInt(key, isOn ? 1 : 0));
    }
    public static void SaveState(this Slider slider, string key)
    {
        key = $"{new System.Diagnostics.StackFrame(1).GetMethod().Name}+{key}";
        slider.value = PlayerPrefs.GetFloat(key, 0f);
        slider.onValueChanged.AddListener(value => PlayerPrefs.SetFloat(key, value));
    }
    public static void SaveState(this InputField inputField, string key)
    {
        key = $"{new System.Diagnostics.StackFrame(1).GetMethod().Name}+{key}";
        inputField.text = PlayerPrefs.GetString(key, string.Empty);
        inputField.onValueChanged.AddListener(value => PlayerPrefs.SetString(key, value));
    }
    public static void SaveState(this Dropdown dropdown, string key)
    {
        key = $"{new System.Diagnostics.StackFrame(1).GetMethod().Name}+{key}";
        dropdown.value = PlayerPrefs.GetInt(key, 0);
        dropdown.onValueChanged.AddListener(value => PlayerPrefs.SetInt(key, value));
    }
}

SaveStateToggleを例に見てみると、やっていることは①PlayerPrefs.GetInt()で取得した値をToggleの初期値として代入し、②Toggleの変更が合った場合のイベント(toggle.onValueChanged)内でPlayerPrefs.SetInt()を呼んでいます。

public static void SaveStateToggle(this Toggle toggle, string key)
{
    key = $"{new System.Diagnostics.StackFrame(1).GetMethod().ReflectedType}+{key}";
    toggle.isOn = PlayerPrefs.GetInt(key, 0) == 1;
    toggle.onValueChanged.AddListener(isOn => PlayerPrefs.SetInt(key, isOn ? 1 : 0));
}

少し工夫しているのかkeyの生成で、System.Diagnostics.StackFrame(1).GetMethod().ReflectedTypeを使って呼び出し元のクラス名を先頭に追加しています。先の例では"hoge.ConfigController+BGMToggle"keyになる形です。こうすることによって、このメソッドを多くの場所で利用してもkeyの衝突が起きにくくしています。

最後に

今回は保存にPlayerPrefsを使っていますが、異常終了時には正しく保存されない場合があります。(PlayerPrefs.Save();で明示的に保存することもできます)

あくまで簡易的なものですので、その点に気をつけてぜひご活用ください。

Discussion