Search Unity

UnityEvent editor in custom editor window

Discussion in 'UGUI & TextMesh Pro' started by TomH, Jul 4, 2015.

  1. TomH

    TomH

    Joined:
    Jul 10, 2012
    Posts:
    41
    Hi.

    I am working on custom editor window that allows editing of multiple objects in a handy way. The objects are derrived from ScriptableObject. I also have derrived my own event class, because I needed a static member in it. In short, it looks something like this:
    Code (CSharp):
    1. [Serializable]
    2. public abstract class BaseEffect : ScriptableObject
    3. {
    4.     public int ID;
    5.  
    6.     public string Name;
    7.  
    8.     public abstract bool CanAttach(SomeOtherClass other);
    9. }
    10.  
    11. [Serializable]
    12. public class MyCustomEvent : UnityEvent<SomeOtherClass>
    13. {
    14.     public static bool Success;
    15. }
    16.  
    17.  
    18. [Serializable]
    19. public class SpecialEffect : BaseEffect
    20. {
    21.     [SerializeField]
    22.     public MyCustomEvent OnCheckEvent;
    23.    
    24.     public override bool CanAttach(SomeOtherClass other)
    25.     {
    26.         if (OnCheckEvent != null)
    27.         {
    28.             OnCheckEvent.Invoke(other);
    29.             return MyCustomEvent.Success;
    30.         }
    31.         return true;
    32.     }  
    33. }
    In my custom EditorWindow, I use the OnGUI-method to draw my controls. I have a list of SpecialEffects (in a simple List<SpecialEffect>). As far as I know, the only way to draw the nice UnityEvent controls, I have to use a SerializedObject and use a PropertyField. I already used that in a custom inspector and it worked well. But in the EditorWindow class there is not serializedObject property, so when selecting a SpecialEffect, I do the following:

    Code (CSharp):
    1. SpecialObject _current;
    2. // some stuff for selecting the special effect
    3. // it is assigned to _current afterwards
    4. SerializedObject = (_current != null) ? new SerializedObject(_current) : null;
    And finally, I want to draw the event editor like this:
    Code (CSharp):
    1. SerializedProperty customEvent = SerializedObject.FindProperty("OnCheckEvent");
    2. EditorGUILayout.PropertyField(customEvent);
    My problem is: I don't get a fancy editor for my UnityEvent, I just get an empty foldout.

    I also tried to set "includeChildren" on true, when drawing the property field. Then I still get a foldout, but it contains all the internal data of my UnityObject.

    How can I get the nice editor for UnityEvents outside of a custom inspector?
     
  2. Doodums

    Doodums

    Joined:
    Feb 19, 2011
    Posts:
    25
    Did you ever come up with a solution for this? I ran into the exact same issue. Trying to do the following:

    Code (CSharp):
    1. MyScriptableObject obj = CreateInstance<MyScriptableObject>();
    2. SerializedObject serObj = new SerializedObject(obj);
    3. SerializedProperty serProp = serObj.FindProperty("MyUnityEvent");
    4. EditorGUILayout.PropertyField(serProp);
    Displays
    http://imgur.com/a/EZ4Qk
     
    Baijiangjun likes this.
  3. ModLunar

    ModLunar

    Joined:
    Oct 16, 2016
    Posts:
    374
    I found a way to do it!

    I have the following Skill class, a ScriptableObject that I want to be able to edit in my custom EditorWindow:
    Code (CSharp):
    1.  
    2. public class Skill : ScriptableObject {
    3.    public UnityEvent onSkillUse;
    4. }
    5.  
    In my EditorWindow class, I have the following variables-- one for the Skill (object that I want to edit, the one that has a UnityEvent), and one for the SerializedObject:
    Code (CSharp):
    1.  
    2. public class SkillDatabaseEditor : EditorWindow {
    3.    private SerializedObject serializedObject;
    4.    private Skill skill;
    5. }
    6.  

    What I found to work is, in the OnGUI() function, I first update the serializedObject. Then, I use the property field with the UnityEvent variable. Finally, I apply the modified properties:
    Code (CSharp):
    1.  
    2. public void OnGUI() {
    3.    //... Other GUI Stuff
    4.    serializedObject.Update();
    5.    EditorGUILayout.PropertyField(serializedObject.FindProperty("onSkillUse"), new GUIContent("On Skill Use"));
    6.    serializedObject.ApplyModifiedProperties();
    7. }
    8.  
    Now, I can make changes in the EditorWindow and see the changes made in the inspector of the saved ScriptableObject .asset file, and modify the .asset file and see the changes made back in the EditorWindow, while getting the nice UnityEvent GUI control! I hope this helps, and let me know if it doesn't work, I might have missed something.

    EDIT: I noticed that if I accidentally re-set the serializedObject by using the constructor again, it broke the link between the two UnityEvent controls and made it problematic again. It seems to be best to make the SerializedObject an instance variable so it does not reset like it would if it was declared in one of the methods.
     
    Last edited: Jul 6, 2017
  4. AMAT_Sooraj

    AMAT_Sooraj

    Joined:
    Sep 20, 2018
    Posts:
    6
    Hey @ModLunar ,
    I'm trying to do something similar. My requirement is that I need to create a Unity Event on a ScriptableObject asset so that I can create UI buttons at runtime with the callbacks of my choosing.
    I got my custom editor to draw the Unity Action but I obviously cant drop scene objects to the event's target field since its on an Asset file.
    I need to know how to replace Unity Event's Object field with a ExposedReference<Object> so that I can drag and drop scene objects. I have already created and editor with a context object (PlayableDirector in the scene). Just dont know how to modify the UnityEvent class.

    Thanks
     
    ModLunar and AuKtagon like this.
  5. AuKtagon

    AuKtagon

    Joined:
    Aug 3, 2017
    Posts:
    7
    Hey @AMAT_Sooraj,

    I am trying to achieve a very similar effect with Unity Events in a custom Editor Window. Have you since figured out how to do this? I have the Unity Events showing correctly in an Editor Window but any changes that I make or references to a Scene do not save.

    Any help is appreciated by you or anything else!

    Thanks!
     
  6. ModLunar

    ModLunar

    Joined:
    Oct 16, 2016
    Posts:
    374
    @AMAT_Sooraj Ah dang, I didn't see your comment until now!

    I don't have en exact answer, but maybe my thoughts below might help spark something:




    I tried this in a ScriptableObject-derived class, and got this to show in the inspector out-of-the-box:

    upload_2020-8-30_16-53-18.png

    upload_2020-8-30_16-53-3.png

    Note that Unity 2020.1 supports serializing the generics there directly. No need to derive a Serializable UnityEvent<T> class unless you wanna be more formal about an event data type used commonly throughout your code.
    However, that field that's highlighted in blue (in "Test D") does NOT allow me to drag scene objects to it.
    ...
    Actually, using an ExposedReference<Object> (yes, using UnityEngine.Object) does NOT allow me to drag scene objects in them period! Then again, I don't know much about the internals of how ExposedReferences work exactly.. they're kind of a nebulous topic to me haha.
    I've heard something about having to implement IExposedProperty in the scene to resolve the references -- but it seemed too complicated for my liking.

    I'm sure if you found a way to get even just an ExposedReference on it's own to serialize properly, then you could dynamically invoke your event through code with the value of that reference.
    -hopes for a Unity dev to jump in and explain how to serialize ExposedReferences in our custom ScriptableObjects-