search
LoginSignup
8

More than 3 years have passed since last update.

posted at

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

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を取得することができた。
コードテンプレート、または自動生成がないとつらい。

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
What you can do with signing up
8