LoginSignup
6
6

More than 5 years have passed since last update.

Unity の inspector から interface をアレしたい

Last updated at Posted at 2017-06-23

やりたかったこと

a. event をいい感じの observable に変換する handler
b. observer
c. subscribe したときに処理されるなんらか

この b と c わりと一緒のクラスに書いちゃうと思うんですが、分けたい!
b の inspector から c を差し替えられるようにしたい!!

例えば

  • drag event をいい感じに n 本指ドラッグ、ピンチインアウトの observable にする handler
  • observer は2個だけ書けばいい
  • ドラッグ、ピンチとでそれぞれ複数の挙動を用意したい
    • 1本指は回転、2本指は移動とか
    • モデルを動かすか、カメラを動かすかとか
  • 挙動を足す度に observer 部分を書きたくない!

uml

(書き方が正しいかあんまり自信ない)

理想

Observer

DragObserver.cs
public class DragObserver : MonoBehaviour
{
    [SerializeField] private IDragHandler handler;
    [SerializeField] private int pointerCount;

    [Inject] private UIDragHandler dragHandler;

    void Start()
    {
        dragHandler.OnDragDeltaAsObservable(pointerCount)
            .Subscribe(handler.OnDrag);
    }
}

interface

IDragHandler.cs
interface IDragHandler
{
    void OnDrag(Vector2 delta);
}

実装

TransformRotator.cs
public class TransformRotator : MonoBehaviour, IDragHandler
{
    public void OnDrag(Vector2 delta)
    {
        Rotate();
    }
}

現実

現実

当然 interface は inspector に表示されません。

どうしても interface を使いたい!案

[SerializeField] を持つ側でよしなにする場合

base class

InterfaceSerializeFieldMonoBehaviour.cs
public class InterfaceSerializeFieldMonoBehaviour<T> : MonoBehaviour
    where T : class
{
    [SerializeField] private MonoBehaviour implementsMonoBehaviour;
    private T _interface;
    protected T Interface
    {
        get
        {
            if (_interface == default(T))
            {
                _interface = implementsMonoBehaviour as T;
            }
            return _interface;
        }
    }

    protected void OnValidate()
    {
        var t = implementsMonoBehaviour as T;
        if (t == default(T))
        {
            implementsMonoBehaviour = null;
        }
    }
}

参考: https://forum.unity3d.com/threads/c-interface-wont-show-in-inspector.383886/#post-2498475

Observer

DragObserver.cs
public class DragObserver : InterfaceSerializeFieldMonoBehaviour<IDragHandler>
{
    [SerializeField] private int pointerCount;

    [Inject] private UIDragHandler dragHandler;

    void Start()
    {
        dragHandler.OnDragDeltaAsObservable(pointerCount)
            .Subscribe(Interface.OnDrag);
    }
}

ふむ

どうしても interface

一応 IDragHandler を実装していない MonoBehaviour は刺せないようにはなっています。

abstract でお茶を濁す案

abstract class

DragObserverBase.cs
public abstract class DragObserverBase : MonoBehaviour
{
    [SerializeField] private int pointerCount;

    [Inject] private UIDragHandler dragHandler;

    void Start()
    {
        dragHandler.OnDragDeltaAsObservable(pointerCount)
            .Subscribe(OnDrag);
    }

    protected abstract void OnDrag(Vector2 delta);
}

実装

TransformRotator.cs
public sealed class TransformRotator : DragObserverBase
{
    protected override void OnDrag(Vector2 delta)
    {
        Rotate(delta);
    }
}

そりゃまあ動く

abstract

どちらもあまり美しくない

  • 今回の場合は abstract でもまあいい気もしてきたけど、 interface で美しく書けないの辛い
  • もしかして Unity クソなのでは?
  • いやいやお前の頭がクソだよというマサカリ募集中
6
6
2

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
6
6