うら干物書き

ゲームを作っています。

【Unity】ギズモをちょっと触ってみたよ

 「ギズモ」と言われると、ドラゴンクエストの雲のモンスターが思い浮かびます。
ギズモとは (ギズモとは) [単語記事] - ニコニコ大百科

 当然のことですが、今日の議題に一切関係ないことです。
 ただ、どうしても雲をいじっている気分になるんですよ。
 こんな気分で勉強できるのでしょうか。


この記事にはUnity2017.2.0f3を使用しています。

バカにだけ見えないというわけではない

 まずはこのシーンビューの画像を見てほしい。
 このシーンには自作位置情報コンポーネントであるPointが配置されているのだが、わかるだろうか。

f:id:urahimono:20171021215655p:plain

 もちろん、シーンビューには見えない。
 Inspector上のGameObjectを選択すれば、ハンドルが出るので位置は特定できる。
 ちなみにPointクラスはこのようなスクリプトになっている。

Point.cs

using UnityEngine;

public class Point : MonoBehaviour
{
    public enum EType
    {
        Item,
        Magic,
        Trap,
    }

    [SerializeField]
    private EType   m_type      = default( EType );
    [SerializeField, Range( 0.0f, 10.0f )]
    private float   m_radius    = 0.0f;

    public EType Type   { get { return m_type; } }
    public float Radius { get { return m_radius; } }

} // class Point

 このPointクラスには「半径」「タイプ」という二つの情報を持っている。
 シーンビュー上からはさっぱりわからない。

 スクリプトの上では各クラスはプロパティを経由して「半径」と「タイプ」の情報を取得することが出来るので、ゲーム内にいるオブジェクト達は問題なく動作出来ることだろう。

 だが、私がシーンビューを見る限りその情報を一切取得することが出来ない。
 このプロジェクトの創造主たる私だけがわからないのだ!
 何というイジメであろうか。

 このような仲間外れがある限り、この国は決してよくなっていかないだろう。
 シーンビュー上で情報が取得できるようにして、良い国を目指していこうと思う。

OnDraw関数でサクッと解決

 さて、というわけでエディタ拡張する必要があるので、Unityエディタ拡張バイブルを開きます。
 Unityが目まぐるしく更新されていく中、随分前に購入したこの本は常に現役なのが素晴らしい。

anchan828.github.io

 バイブルを読む限り、今回はギズモというものの描画処理を追加してあげれば解決できそうだね。
 えーと何々、OnDrawGizmosSelected()を追記すればいいのか。

docs.unity3d.com

Point.cs

void OnDrawGizmosSelected()
{
    Gizmos.color = Color.green;
    Gizmos.DrawSphere( transform.position, 0.1f );
    Gizmos.DrawWireSphere( transform.position, Radius );
}

f:id:urahimono:20171021215711p:plain

 おっ、いいですね。
 範囲がすごくわかりやすく表示されておりまする。

 ただこのOnDrawGizmosSelected()で選択されていないと表示されないみたいですね。
 それはそれでいいんですが、今回シーン中に複数のオブジェクトが配置されています。
 選択されていないオブジェクトも常時ギズモが表示されるようになってもらいたいものです。
 えーとそんなときは……、これだ、OnDrawGizmos()だ。

docs.unity3d.com

Point.cs

void OnDrawGizmos()
{
    Gizmos.color = Color.green;
    Gizmos.DrawSphere( transform.position, 0.1f );
    Gizmos.DrawWireSphere( transform.position, Radius );
}

f:id:urahimono:20171021215722p:plain

 あらあら、いいんじゃないですか。
 これでシーンビューから視覚的に情報が分かるようになって、作業が格段に向上できそうです。
 えがったえがった。

ランタイムの処理とエディタの処理は、どうせ喧嘩するだろうから分けようか

 さて、このままでも一向にかまわないのですが、ランタイムの処理であるPoint.cs部分にエディタ用の処理をがっつり記述するのはちょっと……、という気分になるときがあるかもしれません。

 というわけで、ランタイムの処理とエディタの処理を分けてしまいましょう。
 先ほどのOnDrawGizmosSelected()OnDrawGizmos()は破棄します。

 DrawGizmoAttributeを使えば、別クラスにギズモの描画クラスが記述できるみたいです。

docs.unity3d.com

 さきほどのOnDrawGizmos()OnDrawGizmosSelected()のように、「選択されていない時に表示したい」「選択されたら表示したい」などはDrawGizmoのenumを利用して指定するみたいです。
 DrawGizmoはFlagタイプのようなので、ビットOR演算子で複数指定できそうです。

docs.unity3d.com

 それじゃ、Pointクラスのギズモ描画処理用のPointGizmoEditorクラスを作成しましょう。

PointGizmoEditor.cs

using UnityEngine;
using UnityEditor;

public class PointGizmoEditor
{
    [DrawGizmo( GizmoType.NonSelected | GizmoType.Selected )]
    private static void DrawPointGizmos( Point i_point, GizmoType i_gizmoType )
    {
        Color color = Color.white;

        // 選択されていないときの場合は、色をタイプごと変えてみたよ。
        if( ( i_gizmoType & GizmoType.NonSelected ) != 0 )
        {
            switch( i_point.Type )
            {
                case Point.EType.Item:
                    color   = Color.green;
                    break;
                case Point.EType.Magic:
                    color   = Color.cyan;
                    break;
                case Point.EType.Trap:
                    color   = Color.yellow;
                    break;
                default:
                    break;
            }
        }

        Gizmos.color    = color;

        Vector3 pos     = i_point.transform.position;
        Gizmos.DrawSphere( pos, 0.1f );
        Gizmos.DrawWireSphere( pos, i_point.Radius );
    }

} // class PointGizmoEditor

f:id:urahimono:20171021215733p:plain

 あら素晴らしい。
 先ほどの処理に、Pointクラスのタイプによって色を変える処理も加えてみました。
 これでシーンビューを見るだけで情報が丸わかりになりましたねー。

ゲームビューでも見ようと思えばギズモは見える

 さて、これで今回の作業はこれでおしまいなわけですが、こんな疑問があります。
 このシーンビューで表示したギズモを、ゲームビューでも見えないものでしょうか。
 んー、出来るのかなぁ、そんなこと。
 ギズモって開発用のものだからなぁ。

f:id:urahimono:20171021215744p:plain

 ゲームビューの右上の「Gizmos」ボタンを押すことでゲームビューにも表示できるようですね。
 ただ、ギズモ用の描画処理がかかるため、確実に処理は重くなるので注意が必要です。