Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

List of objects added by function call from editor becomes empty when you enter/leave playing mode

Discussion in 'Scripting' started by Aberdyne, Aug 31, 2016.

  1. Aberdyne

    Aberdyne

    Joined:
    Mar 17, 2015
    Posts:
    64
    Hello Unity community,

    When you call a function of a MonoBehaviour that adds objects to a list from a custom editor script while in editing or playing mode, the list seems to be lost when you transition to the other mode. I guess this is certainly linked to Unity serialization but I wondered if someone had an idea on why exactly it doesn't work and how to do this properly. @superpig @Lucas-Meijer be my guests :)

    Here is a sample code as a repro (I thought it was only happening when transitioning from editing mode to playing mode hence the name):

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEditor;
    3. using UnityEngine;
    4.  
    5. //
    6. // This test reproduces what happens when adding objects to a list through script
    7. // in editing mode or play mode and transitioning to play or editing mode: list becomes empty.
    8. //
    9. [CustomEditor(typeof(TestAddingToListInEditingMode))]
    10. public class TestAddingToListInEditingModeInspector : Editor
    11. {
    12.     private TestAddingToListInEditingMode m_Target;
    13.  
    14.     private void OnEnable()
    15.     {
    16.         m_Target = target as TestAddingToListInEditingMode;
    17.     }
    18.  
    19.     public override void OnInspectorGUI()
    20.     {
    21.         DrawDefaultInspector();
    22.         if (GUILayout.Button("Add Objects"))
    23.         {
    24.             m_Target.AddObjects();
    25.         }
    26.     }
    27. }
    28.  
    29. public class TestAddingToListInEditingMode : MonoBehaviour
    30. {
    31.     [SerializeField]
    32.     private List<GameObject> m_ObjectList = new List<GameObject>();
    33.  
    34.     public void AddObjects()
    35.     {
    36.         for (int i = 0; i < 10; i++)
    37.         {
    38.             var obj = GameObject.CreatePrimitive(PrimitiveType.Cube);
    39.             obj.transform.SetParent(gameObject.transform);
    40.             m_ObjectList.Add(obj);
    41.         }
    42.     }
    43. }
    44.  
     
  2. tomvds

    tomvds

    Joined:
    Oct 10, 2008
    Posts:
    1,028
    You need to tell Unity that you made changes to the object using the EditorUtility.SetDirty function. For example:
    Code (csharp):
    1.     public override void OnInspectorGUI()
    2.    {
    3.        DrawDefaultInspector();
    4.        if (GUILayout.Button("Add Objects"))
    5.        {
    6.             m_Target.AddObjects();
    7.             EditorUtility.SetDirty(m_Target);
    8.        }
    9.    }
    This will solve your issue when going from editor to play mode (and for when you exit Unity). By design, changes happening in play mode never apply to editor mode. If you want to keep changes from play mode, you need to either use copy component or apply the changes to a prefab.
     
  3. Aberdyne

    Aberdyne

    Joined:
    Mar 17, 2015
    Posts:
    64
    Well, of course changes from play mode doesn't persist when leaving it... what was I thinking?! Anyway, in the reverse situation the SetDirty function is working like a charm, thank you very much tomvds!

    The worst is that I've already seen this function but thought it was obsolete or something. The documentation is pretty clear though that it's just not to be used with anything that might be done via the newer Undo.RecordObject... which makes sense in my case but I'll stick with SetDirty right now... I still have some difficulties with Undo support... maybe for another question.
     
  4. tomvds

    tomvds

    Joined:
    Oct 10, 2008
    Posts:
    1,028
    Ah, that new method of saving data escaped my notice. It does seem a lot more convenient, as it also provides undo functionality. The reference guide actually gives a good example on how to use that: http://docs.unity3d.com/ScriptReference/Undo.RecordObject.html. You can probably make it work just by adding a RecordObject call with m_Target as parameter just before the line where you call AddObjects.
     
    superpig likes this.
  5. Aberdyne

    Aberdyne

    Joined:
    Mar 17, 2015
    Posts:
    64
    Actually, I tried... but it seems to be a little bit more complicated than that for my case as there is creation of game objects. I need to group Undo operations under a group, etc. But I hit a wall though as when I perform a Redo my list ends up referring to None instead of the objects recreated... probably doing something wrong here. Thanks anyway.