播放后自定义编辑器重置?
Custom editor resets after Play?
我正在制作自定义编辑器以使用两个 GUI 按钮实例化和销毁多个对象。在编辑模式下,一切正常,我可以实例化多个预制件,然后一个一个地销毁它们,从最后一个实例化到第一个,但是一旦我按下 "Play" 和 "Stop",我我无法销毁任何先前实例化的预制件(在播放模式之前实例化)。我可以实例化新的预制件然后销毁它们,但是对于那些在我点击播放之前实例化的预制件 - 它们不受影响。
现在,我不太担心在播放模式下会发生这种情况,但我绝对想从播放模式之前的那一点继续。
每当实例化预制件时,我都会将其添加到 Stack 中并跟踪其大小。我点击播放-停止后,它似乎重置为0。
在浏览了很多关于类似问题的 post 并检查了 Unity 的 API 之后,我意识到我需要找到一种方法来通过序列化或制作它们来保存自定义编辑器设置和变量脏,我只是不知道如何完成此操作。我已经尝试了那些 post 中的建议,但在我的情况下似乎没有任何效果(或者我做错了什么)。
我有一个 Monobehaviour 脚本和一个 Editor 脚本。我将 post 对象的单一类型的片段,因为其他部分是相同的。
这是第一个:
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);
}
}
}
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() 页面的注意部分,以确保您当前的实施不 运行 违背 Unity 的原则。我不能 link 因为我只有足够的代表 post 2 links...
感谢迈克尔的意见。
我决定放弃 Stack 并继续从最后到第一个一个地删除子对象,如 post 所示:Simple way to Delete the Last Child of a GameObject
播放模式后不再有问题:)
祝你有愉快的一天!
我正在制作自定义编辑器以使用两个 GUI 按钮实例化和销毁多个对象。在编辑模式下,一切正常,我可以实例化多个预制件,然后一个一个地销毁它们,从最后一个实例化到第一个,但是一旦我按下 "Play" 和 "Stop",我我无法销毁任何先前实例化的预制件(在播放模式之前实例化)。我可以实例化新的预制件然后销毁它们,但是对于那些在我点击播放之前实例化的预制件 - 它们不受影响。
现在,我不太担心在播放模式下会发生这种情况,但我绝对想从播放模式之前的那一点继续。
每当实例化预制件时,我都会将其添加到 Stack 中并跟踪其大小。我点击播放-停止后,它似乎重置为0。
在浏览了很多关于类似问题的 post 并检查了 Unity 的 API 之后,我意识到我需要找到一种方法来通过序列化或制作它们来保存自定义编辑器设置和变量脏,我只是不知道如何完成此操作。我已经尝试了那些 post 中的建议,但在我的情况下似乎没有任何效果(或者我做错了什么)。
我有一个 Monobehaviour 脚本和一个 Editor 脚本。我将 post 对象的单一类型的片段,因为其他部分是相同的。
这是第一个:
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);
}
}
}
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() 页面的注意部分,以确保您当前的实施不 运行 违背 Unity 的原则。我不能 link 因为我只有足够的代表 post 2 links...
感谢迈克尔的意见。
我决定放弃 Stack 并继续从最后到第一个一个地删除子对象,如 post 所示:Simple way to Delete the Last Child of a GameObject
播放模式后不再有问题:)
祝你有愉快的一天!