LoginSignup
13
9

More than 5 years have passed since last update.

InterfaceをInspectorでの登録によって取得する

Posted at

ComponentRestriction.gif

前提

UnityはコンポーネントをInspector上でアタッチすることによって参照を取得することができる

Interfaceを使うと疎結合になるため良い設計をするためには必須

Interfaceは通常シリアライズできないためInspectorで登録できない

対応策

  1. Interfaceを実装しているComponentの参照を保持
  2. InterfaceはGetComponentで取得する

サンプル

ISomeInterface.cs
public interface ISomeInterface
{
    void LogAny();
}
SomeController.cs
public class SomeController : MonoBehaviour
{
    // 1. コンポーネントの参照を取得
    [SerializeField] Component someComponent;

    // 2. Interfaceを取得してキャッシュ
    ISomeInterface logger = null;
    ISomeInterface Logger{
        get{
            if(logger == null)
                logger = someComponent.GetComponent<ISomeInterface>();
            return logger;
        }
    }

    void Start()
    {
        Logger.LogAny();
    }
}

SomeControllerのように書くことで、Interfaceを取得することは可能になる。
しかし、このコードではsomeComponentにISomeInterfaceを実装していないコンポーネントでも登録できてしまう。
そこで登録できるコンポーネントに制限をかける。

登録できるコンポーネントに制限をかける

CustomoAttributeを作成する。

ComponentRestrictionAttribute.cs
using System;
using UnityEngine;

[System.AttributeUsage (System.AttributeTargets.Field,Inherited = true, AllowMultiple = false)]
public class ComponentRestrictionAttribute : PropertyAttribute
{
    public Type type;
    public ComponentRestrictionAttribute(Type type){
        this.type = type;
    }
}


ComponentRestrictionDrawer.cs
using UnityEngine;
using UnityEditor;

[CustomPropertyDrawer( typeof ( ComponentRestrictionAttribute ) )]
public class  ComponentRestrictionDrawer : PropertyDrawer
{
    public override void OnGUI (Rect position, SerializedProperty property, GUIContent label)
    {
        var restriction = (ComponentRestrictionAttribute)attribute;

        if (property.propertyType == SerializedPropertyType.ObjectReference) {
            EditorGUI.ObjectField(position, property, restriction.type);
        }else{
            EditorGUI.PropertyField(position, property);
        }
    }
}

ComponentRestrictionDrawerはEditorフォルダ以下に作成

SomeController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SomeController : MonoBehaviour
{
    // ComponentRestriction追加
    [SerializeField, ComponentRestriction(typeof(ISomeInterface))] Component someComponent;

    ISomeInterface logger = null;
    ISomeInterface Logger{
        get{
            if(logger == null)
                logger = someComponent.GetComponent<ISomeInterface>();
            return logger;
        }
    }

    void Start()
    {
        Logger.LogAny();
    }
}

ComponentRrestrictionを追加

これでISomeInterfaceを実装していないコンポーネントは登録できなくなる
GifのAttributeTestは以下

AttributeTest.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AttributeTest : MonoBehaviour, ISomeInterface
{
    public void LogAny()
    {
        Debug.Log("Hello");
    }
}

まとめ

コード量は多くなってしまうもののInterfaceを取得することができた。
コードテンプレート、または自動生成がないとつらい。

13
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
9