入力系のUIを作ろう:InputField・Slider・Toggle・Dropdown【Unityスタートガイド9-5】

名前を入力する、音量をスライダーで調整する、フルスクリーンのチェックを切り替える、画質を選ぶ・・・プレイヤーが値を入力・選択するUIを、まとめてご紹介します。最後に、それらを組み合わせた設定画面を作ってみましょう!

目次

この記事で学べること

  • Input Field(文字の入力)の使い方
  • Slider(スライダー)で値を調整する方法
  • Toggle(チェックボックス)の使い方
  • Dropdown(選択肢から選ぶ)の使い方
  • 値が変わったときに処理を呼ぶ方法(onValueChanged)
  • PlayerPrefsで設定を保存する方法

前提知識

この記事のスクリプトは、どれも先頭に次のusingが必要です(9-4で説明しました)。

using UnityEngine;
using UnityEngine.UI;
using TMPro;

Input Field(文字の入力)

Input Fieldを作る

  • Canvasを右クリック>UI>Input Field – TextMeshPro

Input Fieldの設定

  • Placeholder:何も入力していないときに薄く表示される文字(子のPlaceholderのText Inputで変更)
  • Character Limit:入力できる最大の文字数(0は制限なし)
  • Content Type:入力できる文字の種類(Standard:なんでも、Integer Number:整数だけ、Password:●で隠す など)

日本語を入力する場合は、Input Fieldの中のText(TMP)とPlaceholderのフォントを、9-3で作った日本語のフォントアセットにしておきましょう。

入力された文字を受け取る

「NameInput」という名前でスクリプトを作ります。

using UnityEngine;
using TMPro;

public class NameInput : MonoBehaviour
{
    [SerializeField] private TMP_InputField nameInputField;
    [SerializeField] private TMP_Text greetingText;

    void Start()
    {
        // 入力が確定したとき(Enterを押す・欄の外をクリック)に呼ぶ
        nameInputField.onEndEdit.AddListener(OnNameEntered);
    }

    void OnDestroy()
    {
        nameInputField.onEndEdit.RemoveListener(OnNameEntered);
    }

    private void OnNameEntered(string playerName)
    {
        if (playerName == "")
        {
            greetingText.text = "名前を入力してね";
            return;
        }

        greetingText.text = "ようこそ、" + playerName + "さん!";
    }
}
  • TMP_InputField型で、Input Fieldを参照します
  • inputField.textで、今入力されている文字を読めます
  • onEndEdit:入力が確定したときに呼ばれる。受け取ったメソッドには、入力された文字が渡されます
  • 1文字打つたびに反応させたいときは、onValueChangedを使います

Slider(スライダー)

9-4ではHPバーとして使いましたが、プレイヤーが動かして値を決めるのにも使えます。

Sliderを作る

  • Canvasを右クリック>UI>Slider

Sliderの設定

  • Direction:どちら向きに増えるか(Left To Right など)
  • Min Value / Max Value:値の範囲。音量なら0〜1
  • Whole Numbers:チェックすると整数だけになる

音量を調整する

「VolumeSlider」という名前でスクリプトを作ります。

using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class VolumeSlider : MonoBehaviour
{
    [SerializeField] private Slider volumeSlider;
    [SerializeField] private TMP_Text volumeText;

    void Start()
    {
        volumeSlider.minValue = 0f;
        volumeSlider.maxValue = 1f;
        volumeSlider.value = AudioListener.volume;
        volumeSlider.onValueChanged.AddListener(OnVolumeChanged);
        OnVolumeChanged(volumeSlider.value);
    }

    void OnDestroy()
    {
        volumeSlider.onValueChanged.RemoveListener(OnVolumeChanged);
    }

    // スライダーが動くたびに呼ばれる(今の値が渡される)
    private void OnVolumeChanged(float value)
    {
        AudioListener.volume = value;   // ゲーム全体の音量(0〜1)
        volumeText.text = "音量: " + Mathf.RoundToInt(value * 100) + "%";
    }
}
  • onValueChanged:値が変わるたびに呼ばれ、新しい値が渡されます
  • AudioListener.volumeは、ゲーム全体の音量です。BGMと効果音を別々に調整したい場合は、AudioMixerという仕組みを使います

Toggle(チェックボックス)

Toggleを作る

  • Canvasを右クリック>UI>Toggle
  • 子のLabelの文字を「フルスクリーン」などに変える(Labelは古いText(Legacy)の場合があるので、そのときはTextMeshProのテキストに作り直すか、9-3のフォントを設定します)

Toggleの設定

  • Is On:チェックが入っているか(true / false)
  • Group:同じToggle Groupに入れたToggleは、どれか1つしかOnにならない(ラジオボタンになる)

フルスクリーンを切り替える

「ScreenToggle」という名前でスクリプトを作ります。

using UnityEngine;
using UnityEngine.UI;

public class ScreenToggle : MonoBehaviour
{
    [SerializeField] private Toggle fullscreenToggle;

    void Start()
    {
        fullscreenToggle.isOn = Screen.fullScreen;
        fullscreenToggle.onValueChanged.AddListener(OnFullscreenChanged);
    }

    void OnDestroy()
    {
        fullscreenToggle.onValueChanged.RemoveListener(OnFullscreenChanged);
    }

    private void OnFullscreenChanged(bool isOn)
    {
        Screen.fullScreen = isOn;
        Debug.Log("フルスクリーン: " + isOn);
    }
}
  • toggle.isOnで、今チェックが入っているかを読み書きできます
  • フルスクリーンの切り替えは、エディタの再生中には反映されません。ビルドしたゲーム(第10章)で確認できます

Dropdown(選択肢から選ぶ)

Dropdownを作る

  • Canvasを右クリック>UI>Dropdown – TextMeshPro

Dropdownの設定

  • Options:選択肢のリスト。Inspectorの「+」で追加できる
  • Value:選ばれている選択肢の番号(0から始まる)

画質を選ぶ

選択肢はスクリプトから作ることもできます。プロジェクトに設定されている画質の一覧(Project Settings>Quality)を、そのまま選択肢にしてみましょう。「QualityDropdown」という名前でスクリプトを作ります。

using System.Collections.Generic;
using UnityEngine;
using TMPro;

public class QualityDropdown : MonoBehaviour
{
    [SerializeField] private TMP_Dropdown qualityDropdown;

    void Start()
    {
        // プロジェクトに設定されている画質の名前を、選択肢にする
        qualityDropdown.ClearOptions();
        qualityDropdown.AddOptions(new List<string>(QualitySettings.names));

        // 今の画質を選んだ状態にする
        qualityDropdown.value = QualitySettings.GetQualityLevel();
        qualityDropdown.onValueChanged.AddListener(OnQualityChanged);
    }

    void OnDestroy()
    {
        qualityDropdown.onValueChanged.RemoveListener(OnQualityChanged);
    }

    private void OnQualityChanged(int index)
    {
        QualitySettings.SetQualityLevel(index);
        Debug.Log("画質: " + QualitySettings.names[index]);
    }
}
  • QualitySettings.names:プロジェクトにある画質の名前の一覧(テンプレートによって数が違うので、決め打ちせずにここから作ります)
  • List<string>は、数を後から変えられる配列のようなものです。using System.Collections.Generic;が必要です

PlayerPrefsで設定を保存する

設定した値は、ゲームを終了すると元に戻ってしまいます。音量などの小さな設定は、PlayerPrefsで保存できます。

// 保存(キーの名前と値)
PlayerPrefs.SetFloat("Volume", 0.5f);
PlayerPrefs.SetInt("Fullscreen", 1);
PlayerPrefs.SetString("PlayerName", "勇者");
PlayerPrefs.Save();

// 読み込み(保存されていないときの値も指定する)
float volume = PlayerPrefs.GetFloat("Volume", 1f);
int fullscreen = PlayerPrefs.GetInt("Fullscreen", 1);
string playerName = PlayerPrefs.GetString("PlayerName", "Player");
  • 保存できるのはint・float・stringの3種類。boolは1と0に変えて保存します
  • セーブデータのような大きなデータには向いていません。設定の保存用と考えておきましょう

実践:設定画面を作ろう

ここまでの部品を1つの設定画面にまとめて、設定を保存できるようにしてみましょう。

UIの準備

Canvas
└── SettingsPanel (Panel)
    ├── NameInputField (Input Field - TextMeshPro)
    ├── VolumeSlider (Slider)
    ├── VolumeText (Text - TextMeshPro)
    ├── FullscreenToggle (Toggle)
    ├── QualityDropdown (Dropdown - TextMeshPro)
    └── ResetButton (Button - TextMeshPro)

UIの並べ方は、9-6の記事で紹介するVertical Layout Groupを使うと、きれいに縦にそろえられます。

スクリプト

「SettingsMenu」という名前でスクリプトを作り、SettingsPanelにアタッチします(上で作った部品ごとのスクリプトは使わず、この1つにまとめています)。

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class SettingsMenu : MonoBehaviour
{
    [SerializeField] private TMP_InputField nameInputField;
    [SerializeField] private Slider volumeSlider;
    [SerializeField] private TMP_Text volumeText;
    [SerializeField] private Toggle fullscreenToggle;
    [SerializeField] private TMP_Dropdown qualityDropdown;
    [SerializeField] private Button resetButton;

    void Start()
    {
        qualityDropdown.ClearOptions();
        qualityDropdown.AddOptions(new List<string>(QualitySettings.names));

        LoadSettings();

        nameInputField.onEndEdit.AddListener(OnNameChanged);
        volumeSlider.onValueChanged.AddListener(OnVolumeChanged);
        fullscreenToggle.onValueChanged.AddListener(OnFullscreenChanged);
        qualityDropdown.onValueChanged.AddListener(OnQualityChanged);
        resetButton.onClick.AddListener(ResetToDefaults);
    }

    void OnDestroy()
    {
        nameInputField.onEndEdit.RemoveListener(OnNameChanged);
        volumeSlider.onValueChanged.RemoveListener(OnVolumeChanged);
        fullscreenToggle.onValueChanged.RemoveListener(OnFullscreenChanged);
        qualityDropdown.onValueChanged.RemoveListener(OnQualityChanged);
        resetButton.onClick.RemoveListener(ResetToDefaults);
    }

    private void LoadSettings()
    {
        nameInputField.text = PlayerPrefs.GetString("PlayerName", "Player");
        volumeSlider.value = PlayerPrefs.GetFloat("Volume", 1f);
        fullscreenToggle.isOn = PlayerPrefs.GetInt("Fullscreen", 1) == 1;
        qualityDropdown.value = PlayerPrefs.GetInt("Quality", QualitySettings.GetQualityLevel());

        // 読み込んだ値を、ゲームにも反映する
        ApplyVolume(volumeSlider.value);
        Screen.fullScreen = fullscreenToggle.isOn;
        QualitySettings.SetQualityLevel(qualityDropdown.value);
    }

    private void OnNameChanged(string playerName)
    {
        PlayerPrefs.SetString("PlayerName", playerName);
        PlayerPrefs.Save();
    }

    private void OnVolumeChanged(float value)
    {
        ApplyVolume(value);
        PlayerPrefs.SetFloat("Volume", value);
        PlayerPrefs.Save();
    }

    private void OnFullscreenChanged(bool isOn)
    {
        Screen.fullScreen = isOn;
        PlayerPrefs.SetInt("Fullscreen", isOn ? 1 : 0);
        PlayerPrefs.Save();
    }

    private void OnQualityChanged(int index)
    {
        QualitySettings.SetQualityLevel(index);
        PlayerPrefs.SetInt("Quality", index);
        PlayerPrefs.Save();
    }

    private void ApplyVolume(float value)
    {
        AudioListener.volume = value;
        volumeText.text = "音量: " + Mathf.RoundToInt(value * 100) + "%";
    }

    private void ResetToDefaults()
    {
        // 値を変えると、それぞれのonValueChangedも呼ばれて保存される
        nameInputField.text = "Player";
        OnNameChanged("Player");
        volumeSlider.value = 1f;
        fullscreenToggle.isOn = true;
        qualityDropdown.value = QualitySettings.names.Length - 1;
    }
}

このスクリプトのポイント:

  • Startで読み込んでから、イベントを登録する:先に登録すると、読み込んだ値を入れたときにも保存処理が呼ばれてしまうため
  • 値が変わるたびに保存する:「適用」ボタンを押さなくても、変えた瞬間に保存されます
  • OnDestroyで登録を外す:オブジェクトが消えたあとに呼ばれないようにする片付けです
スライム

設定画面って、部品が多くてInspectorの設定だけで疲れる・・・

フェアリー

Panelでまとめて、名前をちゃんと付けておくと、ドラッグ&ドロップのときに迷わないよ!

よくあるエラーと対処法

エラー:The name ‘AudioSettings’ is ambiguous(あいまいです)

  • 原因:自分で作ったクラスの名前が、Unityに最初からあるクラス(AudioSettings、GraphicsSettingsなど)と同じ
  • 対処法:VolumeSliderやSettingsMenuのように、ほかと重ならない名前にする

エラー:Dropdownの選択肢が表示されない

  • 原因:Optionsが空、またはTemplate(子のオブジェクト)を消してしまった
  • 対処法:Optionsを確認する。Templateを消した場合は、Dropdownを作り直す

エラー:日本語を入力すると□になる

  • 原因:Input Fieldの中のText(TMP)が英語用のフォントのまま
  • 対処法:Text AreaのText(TMP)とPlaceholderのFont Assetを、日本語のフォントアセットにする(9-3の記事)

エラー:Toggleがラジオボタンのように連動しない

  • 原因:Toggle Groupが設定されていない
  • 対処法:空のオブジェクトにToggle Groupを付け、各ToggleのGroupにそれを設定する

エラー:Input Fieldに入力できない

  • 原因:EventSystemがない、またはInteractableが外れている
  • 対処法:シーンにEventSystemがあるか確認する(9-1の記事)

まとめ

  • Input Field:TMP_InputField、確定したときはonEndEdit
  • Slider:valueとonValueChanged(floatが渡される)
  • Toggle:isOnとonValueChanged(boolが渡される)
  • Dropdown:TMP_Dropdown、valueとonValueChanged(番号が渡される)
  • 設定の保存はPlayerPrefs
  • クラス名は、Unityのクラスと重ならないように付ける

次のステップ

リストが長くなってスクロールさせたいとき、部品をきれいに並べたいときの方法を学びましょう:

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメント一覧 (1件)

コメントする

目次