e.blog

主にUnity/UE周りのことについてまとめていきます

カスタムエディタを使ってシーン内にハンドルを表示する

概要

スクリプトをアタッチして、インスペクタからVector3型の値を操作する、というケースはままあるでしょう。
インスペクタから設定する場合、XYZそれぞれの値を手入力で入力して設定していくことになりますが、位置の調整だったり、回転だったり、といったものに利用する値の場合、どうしても細かい数値で調整する必要があります。

すると問題になるのが、「微調整のやりづらさ」。
しかも位置合わせの目的でVector3を用いている場合は、いちいち実行したりして確認する必要があってとてもめんどくさい作業になりがちです。

今回はそんなケースで利用できるカスタムエディタの仕組みについて書きます。

f:id:edo_m18:20161130134028p:plain
↑左の小さいCubeに見えるものはカスタムエディタの機能で、位置を分かりやすく表示しているだけで、GameObjectではありません。

f:id:edo_m18:20161130134031p:plain
↑インスペクタの表記。PositionとRotationを設定する、という想定。

位置と回転を視覚的に表現する

カスタムエディタの中で、以下の機能を利用することで画像のような機能を提供することができるようになります。

  • Handles.PositionHandle
  • Handles.RotationHandle

利用するには以下のように記述します。

var newPos = Handles.PositionHandle(pos, rot);
var posChanges = EditorGUI.EndChangeCheck();

ちなみに上記の処理はOnSceneGUIメソッド内で実行します。

コード自体はシンプルなので、すべて見てもらったほうが分かりやすいと思います。

コード

using UnityEngine;
using System.Collections;

[ExecuteInEditMode]
public class ViewTest : MonoBehaviour
{
    [SerializeField]
    Vector3 _position;

    [SerializeField]
    Vector3 _rotation;

    public Vector3 Position{ get { return _position; } set { _position = value; } }
    public Quaternion Rotation { get { return Quaternion.Euler(_rotation); } set { _rotation = value.eulerAngles; } }
}
using UnityEngine;
using UnityEditor;
using System.Collections;

[CustomEditor(typeof(ViewTest))]
public class ViewTestEditor : Editor
{
    protected virtual void OnSceneGUI()
    {
        var script = target as ViewTest;

        var pos = script.Position;
        var rot = script.Rotation;

        EditorGUI.BeginChangeCheck();
        var newPos = Handles.PositionHandle(pos, rot);
        var posChanges = EditorGUI.EndChangeCheck();

        EditorGUI.BeginChangeCheck();
        var newRot = Handles.RotationHandle(rot, pos);
        var rotChanges = EditorGUI.EndChangeCheck();

        Handles.CubeCap(0, pos, rot, 0.2f);

        if (posChanges || rotChanges)
        {
            if (posChanges)
            {
                script.Position = newPos;
            }
            if (rotChanges)
            {
                script.Rotation = newRot;
            }
        }
    }
}