3
votes

I am making a custom editor to instantiate and destroy multiple objects using two GUI buttons. In edit mode, all is working fine, I can instantiate multiple prefabs, and then destroy them, one by one, from last instantiated to first, but as soon as I press "Play" and the "Stop", I am not able to destroy any previously instantiated prefabs (instantiated before play-mode). I can instantiate new prefabs and then destroy them, but as for those prefabs that were instantiated before I hit play - they stay unaffected.

Now, I am not that much worried that this happens in play mode, but I definitely want to continue from the point before play mode.

Whenever a prefab is instantiated, I add it to a Stack and keep a track of the size. After I hit play - stop, it seems to reset to 0.

After browsing numerous posts about a similar problem and checking Unity's API, I realize I need to figure out a way to save the custom editor settings and variables by serializing them or making them dirty, I just do not know how to accomplish this. I've tried what was suggested in those posts, but nothing seems to be working in my case (or I'm doing something wrong).

I have a Monobehaviour script and an Editor script. I'll post the snippets for a single type of the object, as other parts are the same.

Here is the first one:

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

 [System.Serializable, ExecuteInEditMode]
  public class ObjectControl: MonoBehaviour {

 [SerializeField, HideInInspector]
 public Stack<GameObject> undoStack = new Stack<GameObject>();
 public GameObject instance;
 public int undoStackSize;
 public int objectSelectionIndex = 0;

 public void placeObject()
 {
     switch (objectSelectionIndex)
     {
         case 1:

             Debug.Log("Just received a number 1 from the editor");
             GameObject object_A = Resources.Load("Prefabs/Object_A") as GameObject;
             instance = Instantiate(object_A, this.transform.position, this.transform.rotation, this.transform);

             undoStack.Push(instance);
             undoStackSize = undoStack.Count;

             break;

         case 4:

             Debug.Log("Just received a number 4 from the editor, deleting the object");

             if (undoStack.Count > 0)
             {
                 GameObject objToUndo = undoStack.Pop();
                 DestroyImmediate(objToUndo);
                 undoStackSize--;

             }

             else
             {
                 Debug.Log("Stack is empty! Stack size is: " + undoStack.Count);
             }

             break;
     }
 }

And the Editor script:

using UnityEngine;
using System.Collections;
using UnityEditor;
using System.Collections.Generic;


[CustomEditor(typeof(ObjectControl)), CanEditMultipleObjects]
public class ObjectControlEditor : Editor
 {

 int objectSelectionToolbar = 0;
 int numberOfPossibleUndo;

 bool chooseOption = false;
 bool objectSelectionFoldout = false;

 public ObjectControl scriptTarget;

 public void Awake()
 {
     scriptTarget = (ObjectControl)target;
 }

 public override void OnInspectorGUI()
 {
     DrawDefaultInspector();

     GUI.changed = false;

     chooseOption = EditorGUILayout.Foldout(chooseOption, "Choose a segment to add:");

     if (chooseOption)
     {

         EditorGUILayout.BeginVertical();

         stationSelectionFoldout = GUILayout.Toggle(stationSelectionFoldout, "" + (stationSelectionFoldout ? "▼ Object selection ▼" : "► Object selection ◄"), "Button", GUILayout.MaxWidth(Screen.width), GUILayout.Height(25));

         if (objectSelectionFoldout)
         {

             GUILayout.Space(5);     //Space before a text box
             GUILayout.Box("Select lenght of the station:");
             GUILayout.Space(5);     //Space after a text box and before a toolbox

             string[] objectSelectionToolbarOptions = new string[] { "Object A", "Object B", "Object C" };

             stationSelectionToolbar = GUILayout.Toolbar(objectSelectionToolbar, objectSelectionToolbarOptions, GUILayout.MinWidth(Screen.width), GUILayout.Height(50));
             GUILayout.Space(5);

             RollerCoasterBuilder scriptTarget = (RollerCoasterBuilder)target;
             numberOfPossibleUndo = scriptTarget.undoStackSize;

             switch (objectSelectionToolbar)
             {
                 case 0:

                     GUILayout.BeginHorizontal();

                     if (GUILayout.Button("Place selected object", GUILayout.Height(30)))
                     {
                         scriptTarget.objectSelectionIndex = 1;
                         scriptTarget.PlaceObject();
                     }

                     GUILayout.Space(5);

                     if (GUILayout.Button("Undo" + "(" + numberOfPossibleUndo + ")", GUILayout.Height(30)))
                     {
                         scriptTarget.objectSelectionIndex = 4;
                         scriptTarget.PlaceObject();
                     }

                     GUILayout.EndHorizontal();

                     break;
                 }
            }  
      }
   if (GUI.changed)
      {
      EditorUtility.SetDirty(target);
      }
}
}
2
Don't edit your initial post and add [solved]. That is not how stackoverflow works. You should either mark the best anwer as being the accepted answer, or make your own best answer. If you drop the problem and there is no good answer, you should remove the question.JHBonarius
Thanks J.H.Bonarius, will do next time.RollerMobster

2 Answers

1
votes

Unity cannot serialize the Stack data type. Try converting your undoStack to an Array[] or List<>. You can see a list of serializeable types here: https://docs.unity3d.com/ScriptReference/SerializeField.html

Alternatively, you can write your own serializeble version of a type if Unity does not already support it. see : http://answers.unity3d.com/questions/460727/how-to-serialize-dictionary-with-unity-serializati.html (the second reply).

Also, be sure to read the NOTE section of the EditorUtility.SetDirty() page in the API to make sure that your current implementation isn't running against Unity's grain. I can't link it because I only have enough rep to post 2 links...

0
votes

Thanks Michael for your input.

I've decided to ditch the Stack and carry on with removing child objects, one by one, from last to first, as can be seen in this post: Simple way to Delete the Last Child of a GameObject

No more problems after play-mode :)

Have a nice day!