• 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 /
avatar image
Question by CrowbarSka · May 01, 2017 at 05:16 PM · c#scripting probleminspectoreditor-scriptingcustom-inspector

Reorderable list of UnityEvents

Hi! I'm a bit of a novice with C# but I'm very familiar with many of the Unity tools and concepts. I'd appreciate some help!

I've been following this tutorial, but it doesn't work well when I swap simple variables like floats and strings out for Unity Events.

My goal:

I'm making a scripted event system which could be triggered from anything. It should fire off a list of Unity Events with delays between each one. It should have a custom inspector component so that the list is reorderable.

My problem:

Correctly displaying this list as a Reorderable List in a custom Inspector component.

My setup:

I've created a struct, which uses a UnityEvent (the action) and a float (the delay) for each object in the list.

I then have another script as a container (I think? not too sure of the correct terminology there) which iterates through the list and calls each event in order.

This works exactly how I want it to, but the Inspector tools for this are a bit difficult to work with because it's not reorderable. Here's how it looks by default:

alt text

When I add the custom editor script, everything overlaps each other. Here's the same list with the custom inspector:

alt text

Here's all the code:

The event struct:

 using UnityEngine;
 using UnityEngine.Events;
 using System;
 
 // An event which can be called as part of a Scripted Sequence
 
 [Serializable]
 public struct ScriptedSequenceEvent {
     public float delay;
     public UnityEvent scriptedEvent;
 }

Container for the events. Also processes the list when I call the Scripted Sequence:

 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 
 // A container for the events
 
 public class ScriptedSequence : MonoBehaviour {
 
     private IEnumerator sequenceCoroutine;
 
     public bool startAutomatically;
     public bool onlyTriggerOnce;
     private bool started = false;
 
     // The list of events
     public List<ScriptedSequenceEvent> events = new List<ScriptedSequenceEvent>();
 
     void Start () {
         if (startAutomatically)
             StartScriptedSequence ();        
     }
 
     public void StartScriptedSequence () {
         if (!onlyTriggerOnce) {
             BeginSequence ();
         } else {
             if (!started) {
                 BeginSequence ();
             }
         }
     }
 
     void BeginSequence () {
         started = true;
         sequenceCoroutine = ProcessSequence ();
         StartCoroutine (sequenceCoroutine);
     }
         
     private IEnumerator ProcessSequence () {
         int i = 0;
         // Iterate through each item in the list.
         foreach(ScriptedSequenceEvent currentEvent in events) {
             // Wait for the delay, if it's > 0.
             if (currentEvent.delay > 0f)
                 yield return new WaitForSeconds (currentEvent.delay);
             // Invoke the event.
             currentEvent.scriptedEvent.Invoke ();
             // Increase the current iteration number so we move on to the next one in the next loop.
             i++;
         }
     }
 }


Custom Inspector code:

 using UnityEngine;
 using UnityEditor;
 using UnityEditorInternal;
 
 // The custom inspector script which lets use make the list of events reorderable, and lets us draw it how we want.
 
 [CustomEditor(typeof(ScriptedSequence))]
 public class ScriptedSequence_Editor : Editor {
 
     private ReorderableList list;
 
     private void OnEnable() {
 
         // Create the list
         list = new ReorderableList (serializedObject, serializedObject.FindProperty ("events"), true, true, true, true);
 
         // Draw header label
         list.drawHeaderCallback = (Rect rect) => {
             EditorGUI.LabelField(rect, "Events");
         };
 
         // Draw each element in the list
         list.drawElementCallback = 
             (Rect rect, int index, bool isActive, bool isFocused) => {
             var element = list.serializedProperty.GetArrayElementAtIndex(index);
             rect.y += 2;
             
             EditorGUI.PropertyField (
                 new Rect(rect.x, rect.y, rect.width - 30, EditorGUIUtility.singleLineHeight),
                 element.FindPropertyRelative("scriptedEvent"), GUIContent.none);
 
             EditorGUI.PropertyField (
                 new Rect(rect.x + rect.width - 25, rect.y, 25, EditorGUIUtility.singleLineHeight),
                 element.FindPropertyRelative("delay"), GUIContent.none);
         };
     }
 
     public override void OnInspectorGUI() {
         serializedObject.Update ();
         list.DoLayoutList ();
         serializedObject.ApplyModifiedProperties ();
     }
 }

Thanks in advance! :)

editor1.png (37.9 kB)
editor4.png (15.2 kB)
Comment
JoRouss

People who like this

1 Show 0
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

2 Replies

· Add your reply
  • Sort: 
avatar image
Best Answer

Answer by Adam-Mechtley · May 01, 2017 at 05:19 PM

On your ReorderableList instance, you need to assign something to either elementHeight (when everything has the same height) or elementHeightCallback (when individual elements may have different heights).

Comment
CrowbarSka

People who like this

1 Show 5 · 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
avatar image CrowbarSka · May 01, 2017 at 05:51 PM 0
Share

Thanks!

elementHeight prevented the problem when I add more elements to the list, but the elements can change height when I add multiple events to each element, so it seems like I neeed elementHeightCallback.

Any chance you could give me some pointers for how to implement this?

avatar image Adam-Mechtley CrowbarSka · May 01, 2017 at 05:56 PM 1
Share

It works like any of other callback functions, and most times if you are using e.g., default PropertyDrawers it is sufficient to do something like this:

 list.elementHeightCallback = delegate(int index) {
     var element = list.serializedProperty.GetArrayElementAtIndex(index);
     var elementHeight = EditorGUI.GetPropertyHeight(element);
     // optional, depending on the situation in question and the defaults you like
     // you may want to subtract the margin out in the drawElementCallback before drawing
     var margin = EditorGUIUtility.standardVerticalSpacing;
     return elementHeight + margin;
 };

avatar image CrowbarSka Adam-Mechtley · May 01, 2017 at 11:09 PM 0
Share

Thank you, that code fixed the element height when I add multiple events to each element. However, I still get this issue when I add more elements to the list:

alt text

I guess what I'm looking for is some understanding of how these callbacks work, and how I can add my own and configure them to my needs.

editor5.png (89.5 kB)
Show more comments
avatar image

Answer by Vykx · Oct 31, 2018 at 03:29 AM

@CrowbarSka this should work

 using UnityEngine;
 using UnityEditor;
 using UnityEditorInternal;
 
 [CustomEditor(typeof(ScriptedSequence))]
 public class ScriptedSequence_Editor : Editor
 {
     private ReorderableList list;
     private ScriptedSequence scriptedSequence;
 
     private void OnEnable()
     {
         scriptedSequence = target as ScriptedSequence;
         // Create the list
         list = new ReorderableList(serializedObject, serializedObject.FindProperty("events"), true, true, true, true);
         
 
     }
 
     private void DrawList()
     {
         // Draw header label
         list.drawHeaderCallback = (Rect rect) =>
         {
             EditorGUI.LabelField(rect, "Events");
         };
 
         // Draw each element in the list
         list.drawElementCallback =
             (Rect rect, int index, bool isActive, bool isFocused) =>
             {
                 var element = list.serializedProperty.GetArrayElementAtIndex(index);
                 rect.y += 2;
 
                 EditorGUI.PropertyField(
                      new Rect(rect.x, rect.y, rect.width - 30, EditorGUI.GetPropertyHeight(element,true)),
                      element.FindPropertyRelative("scriptedEvent"), GUIContent.none);
 
                 EditorGUI.PropertyField(
                      new Rect(rect.x + rect.width - 25, rect.y, 25, EditorGUIUtility.singleLineHeight),
                      element.FindPropertyRelative("delay"), GUIContent.none);
             };
 
         list.elementHeightCallback = (int index) =>
         {
             var elementHeight = scriptedSequence.events[index].scriptedEvent.GetPersistentEventCount();
             if (elementHeight >= 1)
             {
                 elementHeight--;
             }
             return (EditorGUIUtility.singleLineHeight * 5) + elementHeight * (EditorGUIUtility.singleLineHeight * 2.7f);
         };
     }
 
     public override void OnInspectorGUI()
     {
         serializedObject.Update();
         DrawList();
         list.DoLayoutList();
         serializedObject.ApplyModifiedProperties();
     }
 }
Comment

People who like this

0 Show 0 · 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.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

330 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 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

There is no GameObject attached to this GameObject 2 Answers

Arrays/Lists in the inspector of Editor Extension scripts 0 Answers

Script to create instance from in inspector 2 Answers

How do I solve a BuildAssetBundles Compilation Error that only occurs in the Editor? 1 Answer

How To Force an Inspector to Repaint 3 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