OnInspectorGUI - Using the default Object Selection popup.

Hi everyone, this seems pretty basic stuff, but I can't seem to get it to work for the life of me so I hoped maybe someone could show me the silly little thing I'm doing wrong to fix it.

I want to build a doubly-linked-list of GameObject nodes that can be placed in the world. Each node has a next node, and a previous node. When I set an objects "Next Node" or "Prev Node" I want both objects to automatically point to each other (the user shouldn't have to go and change both nodes to correctly point to eachother). I can do this by hiding my NextNode and PrevNode members behind accessors, like so:

using UnityEngine;
using System.Collections;

public class CameraNode
    : MonoBehaviour 
{
    // public members //////////////////////////////////////////////

    // public methods ///////////////////////////////////////////////

    // public accessors /////////////////////////////////////////////
    public CameraNode NextNode
    {
        get { return m_nextNode; }
        set
        {
            m_nextNode = value;
            if( ( value != null ) &&
                ( value.PrevNode != this ) )
            {
                value.PrevNode = this;
            }
        }
    }

    public CameraNode PrevNode
    {
        get { return m_prevNode; }
        set
        {
            m_prevNode = value;
            if( ( value != null ) && 
                ( value.NextNode != this ) )
            {
                value.NextNode = this;
            }
        }
    }

    // private methods ///////////////////////////////////////////////

    // private members //////////////////////////////////////////////
    private CameraNode m_nextNode;
    private CameraNode m_prevNode;
}

Now, I do want these nodes editable in the inspector. No worries, I can write an editor script. So I do:

using UnityEngine; using UnityEditor;
using System.Collections;

[CustomEditor(typeof(CameraNode))]
public class CameraNodeEditor   :
  Editor 
{
   public override void OnInspectorGUI()   
   {
    if( target is CameraNode ) //thank you yoyo
    {
      CameraNode editing = (CameraNode)target;
      GameObject nextNodeObj = (GameObject)EditorGUILayout.ObjectField(

                          "Next Node"
                         , editing.NextNode
                         , typeof( CameraNode ) );

      if( nextNodeObj != null )
      {
        editing.NextNode = nextNodeObj.GetComponent<CameraNode>();
      }

      DrawDefaultInspector();
    }
  } 
}

But here's the problem, I'm expecting this (look at the highlighted Test) What I Want

  • I can select an object that only has a particular component.
  • I can select form objects in the world, or prefabs (assets)

But what I get is this: alt text

  • I can only see assets?
  • It looks ugly in the inspector, and non standard.

Now I've seen other questions on the forums that ask this question too, and people recommended a TextField? But that's not really what I want here. Surely this is a reusable component right? How did the Unity developers do it?

Thanks for your time,

  • Howard

It seems that the `ObjectField` never shows scene objects. I guess this is because the object selector doesn't know if the object is going to be stored in a persistent object (prefab) or a scene object, and a prefab is not supposed to be able to ever reference a scene object. I guess we need to figure out a way to handle that.

In the mean time, you can work around it by using a `PropertyField`.

First of all, note that you have to make your variables serialized in order for them to be stored. All `public` variables of supported data types are serialized by default, but `private` variables can also be serialized by using the `[SerializeField]` attribute. This will make them show up in the Inspector, but you can hide them again, using the `[HideInInspector]` attribute:

[HideInInspector]
[SerializeField]
private CameraNode m_nextNode;
[HideInInspector]
[SerializeField]
private CameraNode m_prevNode;

Now, use a PropertyField to show the object field:

using UnityEngine;
using UnityEditor;
using System.Collections;

[CustomEditor(typeof(CameraNode))]
public class CameraNodeEditor : Editor 
{
    SerializedObject m_Object;
    SerializedProperty m_NextNodeProperty;

    void OnEnable ()
    {
        m_Object = new SerializedObject (target);
        m_NextNodeProperty = m_Object.FindProperty ("m_nextNode");
    }

    public override void OnInspectorGUI()   
    {
        EditorGUIUtility.LookLikeInspector();

        if( target.GetType() == typeof( CameraNode ) )
        {
            CameraNode editing = (CameraNode)target;

            CameraNode nodeBefore = editing.NextNode;
            EditorGUILayout.PropertyField (m_NextNodeProperty);
            if (m_NextNodeProperty.objectReferenceValue as CameraNode != nodeBefore)
            editing.NextNode = m_NextNodeProperty.objectReferenceValue as CameraNode;

            DrawDefaultInspector();
        }
    }
}

I have confirmed that to work fine. The scene objects are displayed.

Note that using `EditorGUIUtility.LookLikeInspector();` will make the controls look like default inspector controls. We are moving away from that ourselves though; you'll notice that a lot of components in Unity 3 have different look; for example the Camera component, Light component, and some more.