How do I build a custom editor that iterates over a scene hierarchy and presents all the controls for Springs in one UI?

Here’s the context:

I have a puppet with a set of multitouch controls that depend on a network of spring joints - visualised below with the colored handles and the lines. It’s working nicely, but I’d like a custom inspector that collects all the relevant springjoint2D settings into one UI (in the inspector and eventually in the scene and game GUI.

So: the problems at the moment are:

(1) the spring float fields are readonly and not editable.

(2) I get an error at line 30 in SpringScriptEditor.cs: NullReferenceException: Object reference not set to an instance of an object. This I’ve read about elsewhere and don’t know if it is related to (1).


The hierarchy of controls looks like this (a springJoint is on each controller):

        |------Controller 1
                  |------Controller 2
                                    |------Controller 3
                                    |------Controller 3 a
                                    |------Controller 4
                                    |------Controller 4a

Here’s the result, followed by the code, which makes me feel I’m nearly there - though I don’t think I get SerializedProperties / Objects properly yet - and I’ve tried several of the approaches on ‘answers’.

(1) Here’s the basic object class: GetSprings.cs

using System.Collections;
using System.Collections.Generic;

public class GetSprings : MonoBehaviour {

	public GameObject[] puppets;

	public GameObject[] myObject {
		get {return puppets;}


(2) The Custom Editor Script (SpringsScriptEditor.cs)

using UnityEngine;
using System.Collections;
using UnityEditor;


public class SpringsScriptEditor : Editor {

	//SerializedProperty puppets;

	void OnEnable()
		//puppets = serializedObject.FindProperty("puppets");

	public override void OnInspectorGUI() {

		var t = target as GetSprings;
		SerializedProperty tps = serializedObject.FindProperty ("puppets");
		EditorGUILayout.PropertyField(tps, true);

		//NullReferenceException: Object reference not set to an instance of an object
		// error here when array doesnt exist?

		foreach (GameObject puppet in t.puppets) {

	void Traverse(GameObject obj) {

		if (obj != null) {
			foreach (Transform child in obj.transform) {

				Component[] springJoints;
				springJoints = child.gameObject.GetComponents( typeof(SpringJoint2D) );
				//Debug.Log("Parent Object: ";
				foreach (SpringJoint2D spring in springJoints) {
					//EditorGUILayout.LabelField(, );
					if (spring) {
		EditorGUILayout.FloatField( " Frequency", spring.frequency);
		EditorGUILayout.FloatField( " Damping", spring.dampingRatio);
		EditorGUILayout.FloatField( " Distance", spring.distance);
			if(EditorGUI.EndChangeCheck()) {
						//Debug.Log("Parent: ""

// "Connected Body: “+spring.connectedBody+”
// "Distance: “+spring.distance+”
// "Damping: “+spring.dampingRatio+”
// "Frequency: “+spring.frequency+”

I hope I’m missing something simple…

Thanks in advance.


That’s fantastic. Thank you for such a detailed answer. I was on the right track - and used lists in a more ‘manual’ solution. I was looking at a custom class, getters and setters etc. but your walk-though has drawn that all together and the principle of moving it into a custom editor / custom window is working too. I read the catlikecoding tutorial and found that helpful. Thank you for your help.

I collect all the puppet controls (for live performance) into a GUI window. And exposing the spring settings helps speed up setting the objects. I’ve adjusted this to work in the editor.

I needed to make public the refresh method. And in the non-editor version had to call refresh from update in order for the slider GUI changes to effect the springs. Shame there isn’t a method that updates on GUI change. In the editor script this works as expected.

void Refresh()


public void Refresh()

Also, I added the [Range…] attributes. Thanks to you I get it a lot more! Cheers!


ps. If you promote the comment to an ‘answer’ - I’ll up-vote it and mark it as the answer… cheers.