How do you make a custom inspector for a class or instance?

I have a class that looks like this:

[Serializable]
public class Encounter{
	public string[] encounterEnemy;
}

I want custom inspector stuff that shows up when this class is part of other classes, arrays etc (in this case, I want the encounterEnemy to show up as a drop down list, but that is not really important).

I can make custom inspector GUI for variables found in the main body of scripts, but I can’t seem to do anything with any other classes, even if they inherit from monobehavior.

Here is an example of something I am trying that does not work:

The script named TestScript

using UnityEngine;
using System.Collections;
using System;


public class TestClass : MonoBehaviour{
		public int testInt;
}

The script named TestClassEditor

using UnityEngine;
using UnityEditor;
using System.Collections;




[CanEditMultipleObjects]
[CustomEditor(typeof(TestClass))]//notice that this refers to the class declaration and not the main script
public class TestClassEditor : Editor {

	SerializedObject testClass; 
	
	SerializedProperty testInt;
	
	string[] junk = {"things","stuff","whatever"};
	
	void OnEnable()
	{
			
		testClass = new SerializedObject(target);

		testInt = testClass.FindProperty("testInt");

	}
	
	public override void OnInspectorGUI () {
		testClass.Update();
		
		testInt.intValue = EditorGUILayout.Popup("Enemy",testInt.intValue,junk);
		
		testClass.ApplyModifiedProperties();
	}			

}
    public class TestScript : MonoBehaviour {
    
    	public TestClass testClassInst;
    		
    }

Other posts (I have searched extensively) seem to suggest that doing this for instances of the class(not the class itself) but I have not been able to figure out how that might be done in an array or as part of another class.

This is what I ultimately did to write an inspector for a class that was part of an array that was part of several other classes. If you don’t want to search through the fairly ugly code, the takeaway is that you can use SerializedProperty Methods GetArrayelementAtIndex() and FindPropertyRelative() to and the property arraySize to drill down through Serialized classes and arrays in basically the same way you would in your regular code. Infact, you could use regular array methods if you are just setting things directly with target. Note that this is very ugly in the Inspector because I don’t really understand formatting yet.

    [Serializable]
    public class Enemy{ //this is not the same as enemy in the editor script which is just a string
    	public string name;
    	public GameObject prefab;
    	public int health;
    	public int curHealth;
    	public int damage;
    	
    	
    	public void SetFromPrefab()
    	{
    		name = prefab.name;
    		EnemyBaseStats enemyBaseStats = prefab.GetComponent<EnemyBaseStats>();
    		health = enemyBaseStats.health;
    		curHealth = enemyBaseStats.curHealth;
    		damage = enemyBaseStats.damage;		
    		
    	}
}
    
    [Serializable]
    public class Encounter{
    	public string[] encounterEnemies;
    }
    
    [Serializable]
    public class Zone{
    	public string name;
    	public int encounterPercent;
    	public Encounter[] zoneEncounters = new Encounter[0];   	
    }
    
    
    [Serializable]
    public class PC{
    	public string name;
    	public GameObject PCPrefab;
    	public Ability[] abilities;
    	public int damage;
    	public int health;
    	public int maxHealth;    
    }
    
 


public class Uni : MonoBehaviour {
	
	
	public Enemy[] preAllEnemies;

	public Zone[] preZones;
    }

Then the Editor

[CustomEditor(typeof(Uni))]

[CanEditMultipleObjects]

public class DropDownMenu : Editor {

	private int index;
	private string[] preAllEnemiesString;
	private Uni uniEdNS;
	
	private SerializedObject uniSR;
	private SerializedProperty
			preZones;
	
	void OnEnable()
	{
		uniSR = new SerializedObject(target);
		preZones = uniSR.FindProperty("preZones");
		uniEdNS = (Uni)target;
		preAllEnemiesString = new string[uniEdNS.preAllEnemies.Length];
		
		for(int x = 0; x < uniEdNS.preAllEnemies.Length; x++)
		{
			preAllEnemiesString[x] = uniEdNS.preAllEnemies[x].prefab.name;
		}
	}
	
	public override void OnInspectorGUI () {
		
		uniSR.Update();
		

		for (int k = 0; k < preZones.arraySize; k++) //SerializedProperty has its own properties and methods for dealing with arrays: arraySize, GetArrayElementAtIndex() are used to drill down through my class to get to the strings
		{
			EditorGUILayout.LabelField("Zone " + k); //these are just labels to help organize what this looks like in the inspector window. It is really ugly right now because I don't yet understand formating
			
			SerializedProperty zone = preZones.GetArrayElementAtIndex(k);
			SerializedProperty encounters = zone.FindPropertyRelative("zoneEncounters");//I did not think this would work but it did. FindPropertyRelative uses the path of the SerializedProperty (in this case whichever zone is currently being delt with) and adds the argument to get a SerializedProperty one level down
			
			for (int l = 0; l < encounters.arraySize; l++)
			{
				EditorGUILayout.LabelField("encounter " + l);
				EditorGUILayout.BeginVertical();//more formatting
			
				SerializedProperty encounter = encounters.GetArrayElementAtIndex(l);
				SerializedProperty encounterEnemies =  encounter.FindPropertyRelative("encounterEnemies");
				
				for(int m = 0; m < encounterEnemies.arraySize; m++)
				{
					SerializedProperty enemy = encounterEnemies.GetArrayElementAtIndex(m);
					
					for(int j = 0; j < preAllEnemiesString.Length; j++)//the way I have it set up, the value that is actualy stored is the string. But popups use and return ints. This checks the stored string and sets the popup accordingly
					{
						
						if (enemy.stringValue == preAllEnemiesString[j]) 
						{
							index = j;
							
						}
						
					}
					
					
						index = EditorGUILayout.Popup("Enemy",index,preAllEnemiesString);
						enemy.stringValue = preAllEnemiesString[index];// this uses the value I get from the popup as an index to get the correct string. I can move elements of preAllEnemies around and no harm will be done to the enemy values, but if a value is not found in the preAllEnemies list, the enemy will revert to 0.
					
					
					
				}
				


				EditorGUILayout.EndVertical();
					
			}
			
		}
		
		uniSR.ApplyModifiedProperties();
		DrawDefaultInspector ();
	}
    }

You can’t yet; wait for Unity 4.

Is this what you’re looking for, or did I misinterpret the question? (Maybe it’s a C#-specific issue? Unityscript is so lazy by comparison but I don’t trust my C#-ing for inspectors yet)

I don’t know of a way to write an Inspector for an inner class, but I’ve been working around it for a while this way:

[SomeEncounters.js]

class SomeEncounters extends MonoBehaviour {
  class Encounter {
    var monster : int;
    function InspectorGUI() {
      monster = EditorGUILayout.Popup( ... );   
    }
  }
  var encounter : Encounter;
}

[SEEdit.js]

@CustomEditor(SomeEncounters)
class SEEdit extends Editor {
  function OnInspectorGUI() {
    super.OnInspectorGUI();
    target.encounter.InspectorGUI();
  }
}

You’d still have to write the custom inspector for any class that uses the encounter (SomeEncounters in this case), but this is how I’ve been making class-specific inspectors for a while now.

You could have an array of Encounters, just have to set the size with an IntField and call the InspectorGUI on each element.