かなり地味ですがわかりづらいのでメモ。
エディタ拡張でHandleCapのクリックイベントを取得する方法です。
ソースコード
いきなりですがソースコードです。
using UnityEngine; using UnityEditor; public class SceneGUIExample : MonoBehaviour { } [CustomEditor(typeof(SceneGUIExample))] public class SceneGUIExampleEditor : Editor{ private bool _cached = false; private int _controlId; private SceneGUIExample _target; private bool _isSelected = false; private void OnSceneGUI(){ if (!_cached) { // ControlIdを割り振る _controlId = GUIUtility.GetControlID(FocusType.Passive); _target = target as SceneGUIExample; _cached = true; } // 今のEventTypeにより処理を分ける if (Event.current.type == EventType.Repaint || Event.current.type == EventType.Layout) { Handles.color = _isSelected ? Color.red : Color.white; Handles.SphereHandleCap(_controlId, _target.transform.position, _target.transform.rotation, 1.0f, Event.current.type); } else if (Event.current.type == EventType.MouseDown) { // クリックした部分にあるもののControlIdが一致したら選択中とする _isSelected = HandleUtility.nearestControl == _controlId; } } }
まず、このHandleCapを識別するためのControlIdを取得する必要があります。
これに関してはGUIUtility.GetControlID(FocusType.Passive)で取得することでUnityにより割り振られます。
また、OnSceneGUIはレイアウトの前処理や描画時、マウスイベント時など様々なイベントをトリガーとして呼ばれます。
これを判定するのがEvent.current.typeです。
HandleCapのイベントを取る時には、上例のようにイベントがEvent.LayoutとEvent.Repaintの時の両方でHandleCapのメソッドを呼びます。
(Handles.Colorの変更はRepaint時だけでも問題ないです)
そしてMouseDownイベントでクリックを判定します。
HandleUtility.nearestControlでクリック箇所にあるHandleのControlIdが得られるため、これを最初に発行したControlIdと比較します。
これでHandleのクリックを取ることができます。
もちろん他のHandleCapでも同様です。
ちなみにEvent.Layoutは全てのイベントの前に行われる処理で、自動レイアウトシステムから使われるとのこと。
詳細は不明ですが、Event.Layoutで処理を行わないとクリック判定が行われませんでした。
また、Event.Repaintは描画時の処理で、ここでHandleの処理を書かないと描画がされませんでした。
参考
gui - Use Unity Handles for interaction in the scene view - Game Development Stack Exchange
Cygames Tech Fes フォローアップ: 内製タイムラインツールCuttの紹介 | Cygames Engineers' Blog