Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
  • Help Room /
avatar image
0
Question by ianjgrant · Oct 12, 2016 at 10:10 PM · c#uieditor-scriptingspring

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).

alt text

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

 Scene
   |---PuppetRoot_Wayang
         |------Controller 1
                   |------Controller 2
                            |------RodController
                                     |------Controller 3
                                     |------Controller 3 a
                                     |------Controller 4
                                     |------Controller 4a
 etc...

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'.

alt text

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

 using System.Collections;
 using System.Collections.Generic;
 
 [System.Serializable]
 public class GetSprings : MonoBehaviour {
 
     public GameObject[] puppets;
 
     public GameObject[] myObject {
         get {return puppets;}
     }
 }

And

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

 using UnityEngine;
 using System.Collections;
 using UnityEditor;
 
 [CustomEditor(typeof(GetSprings)),CanEditMultipleObjects]
 
 public class SpringsScriptEditor : Editor {
 
     //SerializedProperty puppets;
 
     void OnEnable()
     {
         //puppets = serializedObject.FindProperty("puppets");
     }
 
     public override void OnInspectorGUI() {
 
         serializedObject.Update();
         var t = target as GetSprings;
         SerializedProperty tps = serializedObject.FindProperty ("puppets");
         EditorGUI.BeginChangeCheck();
         EditorGUILayout.PropertyField(tps, true);
         if(EditorGUI.EndChangeCheck())
         serializedObject.ApplyModifiedProperties();
         
 
         //NullReferenceException: Object reference not set to an instance of an object
         // error here when array doesnt exist?
 
         foreach (GameObject puppet in t.puppets) {
                         
             Traverse(puppet);
             //Debug.Log(puppet.name);        
         }
     }
 
     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: "+obj.name);
                 foreach (SpringJoint2D spring in springJoints) {
                     //EditorGUILayout.LabelField(obj.name, );
                     if (spring) {
         EditorGUI.BeginChangeCheck();
         EditorGUILayout.LabelField(spring.gameObject.name,EditorStyles.boldLabel);
         EditorGUILayout.FloatField(spring.gameObject.name+ " Frequency", spring.frequency);
         //EditorGUILayout.Slider(spring.frequency,0.0f,200f);
         EditorGUILayout.FloatField(spring.gameObject.name+ " Damping", spring.dampingRatio);
         //EditorGUILayout.Slider(spring.dampingRatio,0.0f,200f);
         EditorGUILayout.FloatField(spring.gameObject.name+ " Distance", spring.distance);
            //EditorGUILayout.Slider(spring.distance,0.0f,10f);
             if(EditorGUI.EndChangeCheck()) {
                 serializedObject.ApplyModifiedProperties();
             }                
                         //Debug.Log("Parent: "+spring.gameObject.name+"\r\n"+
                         //    "Connected Body: "+spring.connectedBody+"\r\n"+
                         //    "Distance: "+spring.distance+"\r\n"+
                         //    "Damping: "+spring.dampingRatio+"\r\n"+
                         //    "Frequency: "+spring.frequency+"\r\n");
                     }
                 }
                 Traverse(child.gameObject);
             }    
         }
     }
 }


I hope I'm missing something simple...

Thanks in advance.

Ian

screen-640x480-2016-10-12-22-31-53.png (317.9 kB)
result.png (110.9 kB)
Comment
Add comment · Show 2
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image b1gry4n · Oct 14, 2016 at 02:57 AM 0
Share

A class might be easier to access the data

   [System.Serializable]
 public class JointInfo
 {
     public string name;
     public SpringJoint2D joint;
     public float frequency;
     public float dampingRatio;
     public float distance;
 
     public JointInfo(SpringJoint2D joint)
     {
         this.joint = joint;
         this.name = joint.transform.gameObject.name;
 
         this.frequency = joint.frequency;
         this.dampingRatio = joint.dampingRatio;
         this.distance = joint.distance;
     }
 
     //helper functions since you mentioned updating these on the fly
     public void Frequency(float val)
     {
         this.frequency = val;
         Refresh();
     }
     public void DampingRatio(float val)
     {
         this.dampingRatio = val;
         Refresh();
     }
     public void Distance(float val)
     {
         this.distance = val;
         Refresh();
     }
     //
 
     void Refresh()
     {
         this.joint.frequency = this.frequency;
         this.joint.dampingRatio = this.dampingRatio;
         this.joint.distance = this.distance;
     }
 }

GetComponentsInChildren will get all of the components in all of the children of a game object. I would store these in a list

If you are trying to collect all the spring joints in a game object you can call

  using System.Collections.Generic;
     public List<JointInfo> jointInfoList;
     void Start()
     {
         jointInfoList = new List<JointInfo>();
     }
     public void Traverse(GameObject obj)
     {
         SpringJoint2D[] joints = obj.GetComponentsInChildren<SpringJoint2D>();
         foreach (SpringJoint2D sj in joints)
         {
             jointInfoList.Add(new JointInfo(sj));
         }
     }

now you can simply iterate through a list with a for loop to access any joint and change/modify parameters using the class built in functions. You can do a lot with the default inspector UI, so unless you are looking for something really fancy you could probably stick with that. Lets say you want to have a slider for the frequency that has a range between 0.0 and 1.0. just add [Range(0.0f, 1.0f)] above the variable. Want to add a tooltip that pops up when you over over the variable name? [Tooltip("Insert text")]

 [Tooltip("The frequency at which the spring oscillates around the distance distance between the objects.")]
 [Range(0.0f, 1.0f)]
 public float frequency;

avatar image b1gry4n b1gry4n · Oct 14, 2016 at 03:15 AM 0
Share

Turning this in to an editor script function is not any different, you just need to call the function from the editor with a button. Here is a really good tutorial on custom lists in the editor: http://catlikecoding.com/unity/tutorials/editor/custom-list/

For example. Your editor script could include something like...

 public override void OnInspectorGUI()
     {
         YourScriptName jointController = (YourScriptName)target;
 
         if (DrawDefaultInspector())
         {
             //this is where you would call a function in the "jointController" script to update the variables.
             //This will be called when any value is changed.
             jointController.UpdateValues();
         }
 
         //and a button to manually update
         if (GUILayout.Button("Update"))
         {
             jointController.UpdateValues();
         }    
     }

and inside the "jointController" script...

     public void UpdateValues()
     {
         foreach (JointInfo ji in jointInfoList)
         {
             ji.Refresh();
         }
     }

1 Reply

· Add your reply
  • Sort: 
avatar image
0

Answer by ianjgrant · Oct 19, 2016 at 10:06 AM

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()

Changed:

 public void Refresh()

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

Ian

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

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

261 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

UI Text is not being rebuilt/updated in edit mode, when changing text from OnInspectorGUI 1 Answer

How to make mesh render objects overlay UI? 1 Answer

UI element bug? 1 Answer

RectTransform Left Right Bottom Top 0 Answers

In Editor - Update Material and save it to disk 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges