はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【Unity】MonoBehaviour.OnValidate()とMonoBehaviour.Reset()でコンポーネントのプロパティの設定を楽にする

はじめに

今回はMonoBehaviour.OnValidate()MonoBehaviour.Reset()について取り上げたいと思います。

MonoBehaviour-Reset() - Unity スクリプトリファレンス
MonoBehaviour-OnValidate() - Unity スクリプトリファレンス

これらのメソッドを利用することで、コンポーネントをアタッチすると自動でプロパティに参照をつけたり、一括でコンポーネントの値をいじったりすることができます。

f:id:hanaaaaaachiru:20211111210255g:plain
一括でプロパティをいじる

早速みていきましょう。

MonoBehaviour.OnValidate()

この関数はスクリプトがロードされた時やインスペクターの値が変更されたときに呼び出されます(この呼出はエディター上のみ)

docs.unity3d.com

インスペクターからプロパティをいじった際に発火されるメソッドだと覚えておけばOKです。

MonoBehaviour.Reset()

デフォルト値にリセットします

docs.unity3d.com

公式ドキュメントはだいぶ簡素ですが、リセットをした際に呼ばれるメソッドになります。

使い方

public class Sample : MonoBehaviour
{
    [SerializeField] private int value;
    
    /// <summary>
    /// インスペクターのリセットボタンが押されたら実行される
    /// </summary>
    private void Reset()
    {
        Debug.Log("Reset");
    }
    
    /// <summary>
    /// スクリプトがロードされた時やインスペクターの値が変更されたときに呼び出される(エディター上のみ)
    /// </summary>
    /// <returns></returns>
    private void OnValidate()
    {
        Debug.Log("OnValidate");
    }
}

MonoBehaviorを継承しているクラスでReset()OnValidate()を定義します。

Resetは以下のタイミングで呼ばれます。

  • コンポーネントをアタッチしたとき
  • インスペクターのResetボタンを押したとき
f:id:hanaaaaaachiru:20211111203703p:plain
Resetボタン


対してOnValidateは以下のタイミング。

  • コンポーネントをアタッチしたとき
  • インスペクター上のプロパティをいじったとき

応用例

アタッチ時に参照をつける

よく利用される例として、コンポーネントをアタッチした際に自動で参照をつけることに用います。

[RequireComponent(typeof(Rigidbody))]
public class Sample : MonoBehaviour
{
    [SerializeField] private Rigidbody value;
    
    /// <summary>
    /// インスペクターのリセットボタンが押される&アタッチ時に呼ばれる
    /// </summary>
    private void Reset()
    {
        // RequireComponent属性より、必ずGetComponentできることが保証されている
        value = GetComponent<Rigidbody>();

        // Rigidbodyがアタッチされていることが保証されていないなら、TryGetComponentを利用する
        if (TryGetComponent(out Rigidbody rigidbody))
        {
            value = rigidbody;
        }
    }
}
f:id:hanaaaaaachiru:20211111210555g:plain
Reset

他のコンポーネントの値を変更する

インスペクター上のプロパティの値が変わった際に、他のコンポーネントのプロパティをいじるなんてこともできます。

DynamicBoneを利用した際に、一つのゲームオブジェクトに同じコンポーネントがたくさんついていて、一つ一ついじるのがめんどくさいといったときに活躍してくれました。

[RequireComponent(typeof(Example))]
public class Sample : MonoBehaviour
{
    [SerializeField] private int value;

    /// <summary>
    /// スクリプトがロードされた時やインスペクターの値が変更されたときに呼び出される(エディター上のみ)
    /// </summary>
    /// <returns></returns>
    private void OnValidate()
    {
        var example = GetComponent<Example>();

        // publicな変数なら直接いじる
        example.value = value;

        // privateな変数ならリフレクションを利用
        example.GetType()
            .GetField("privateValue", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
            ?.SetValue(example, value);
    }
}

public class Example : MonoBehaviour
{
    public int value;
    [SerializeField] private int privateValue;
}
f:id:hanaaaaaachiru:20211111210255g:plain
OnValidateを使った様子