【问题标题】:Custom editor resets after Play?自定义编辑器在播放后重置?
【发布时间】:2017-07-13 02:05:48
【问题描述】:

我正在制作一个自定义编辑器,以使用两个 GUI 按钮实例化和销毁多个对象。在编辑模式下,一切正常,我可以实例化多个预制件,然后从最后一个实例化到第一个实例一个一个地销毁它们,但是一旦按下“播放”和“停止”,我就无法销毁任何先前实例化的预制件(在播放模式之前实例化)。我可以实例化新的预制件然后销毁它们,但对于那些在我点击播放之前实例化的预制件 - 它们不受影响。

现在,我不太担心在播放模式下会发生这种情况,但我肯定想从播放模式之前的那一点继续。

每当实例化预制件时,我都会将其添加到堆栈中并跟踪其大小。在我点击播放 - 停止后,它似乎重置为 0。

在浏览了许多关于类似问题的帖子并检查了 Unity 的 API 之后,我意识到我需要找到一种方法来通过序列化或使它们变脏来保存自定义编辑器设置和变量,我只是不知道如何完成这个.我已经尝试了这些帖子中的建议,但在我的情况下似乎没有任何效果(或者我做错了什么)。

我有一个 Monobehaviour 脚本和一个编辑器脚本。我将发布单一类型对象的 sn-ps,因为其他部分相同。

这是第一个:

 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;
     }
 }

还有编辑器脚本:

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);
      }
}
}

【问题讨论】:

  • 不要编辑您的初始帖子并添加 [已解决]。这不是stackoverflow的工作方式。您应该将最佳答案标记为已接受的答案,或者自己制作最佳答案。如果你放弃了这个问题并且没有好的答案,你应该删除这个问题。
  • 谢谢J.H.Bonarius,下次会做。

标签: c# unity3d unity5


【解决方案1】:

Unity 无法序列化 Stack 数据类型。尝试将您的 undoStack 转换为 Array[] 或 List。您可以在此处查看可序列化类型的列表:https://docs.unity3d.com/ScriptReference/SerializeField.html

或者,如果 Unity 不支持它,您可以编写自己的类型的可序列化版本。见:http://answers.unity3d.com/questions/460727/how-to-serialize-dictionary-with-unity-serializati.html(第二次回复)。

此外,请务必阅读 API 中 EditorUtility.SetDirty() 页面的 NOTE 部分,以确保您当前的实现没有违反 Unity 的规范。我无法链接它,因为我只有足够的代表来发布 2 个链接...

【讨论】:

    【解决方案2】:

    感谢迈克尔的意见。

    我决定放弃 Stack 并继续从最后一个到第一个删除子对象,如这篇帖子所示:Simple way to Delete the Last Child of a GameObject

    播放模式后没有更多问题:)

    祝你有美好的一天!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-22
      • 1970-01-01
      • 2015-02-06
      相关资源
      最近更新 更多