[英]Unity ScriptableObject Polymorphic Arrays Serialization
主要問題是,我正在嘗試在 ScriptableObject 中使用多態列表,但在重新啟動 Unity 時其內容會丟失; 下面的代碼。
所以我有一個基礎 class:
[Serializable]
public class BaseAction : ScriptableObject
{
public virtual void OnGUI()
{
}
public virtual void ExecuteAction()
{
}
}
還有一個繼承 class 的簡單字符串屬性:
[Serializable]
public class DebugLogAction : BaseAction
{
[SerializeField]
private string debugText = default;
public override void OnGUI()
{
debugText = EditorGUILayout.TextField(debugText);
}
public override void ExecuteAction()
{
Debug.Log(debugText);
}
}
它們都在一個包含 BaseAction 列表的 ScriptableObject 中重新組合:
[Serializable]
[CreateAssetMenu(fileName = "NewActionContainer", menuName = "ScriptableObjects/Action Container")]
public class ActionContainer : ScriptableObject
{
[SerializeField]
private List<BaseAction> actions = default;
public void OnEnable()
{
if (actions == null)
{
actions = new List<BaseAction>();
}
}
public void OnInspectorGUI()
{
foreach (var action in actions)
{
action.OnGUI();
}
if (GUILayout.Button("Add Debug Log Action"))
{
actions.Add(CreateInstance<DebugLogAction>());
}
}
}
我已經為 ActionContainer ScriptableObject 編寫了一個自定義編輯器,它工作正常,顯示用於添加多個操作的按鈕,該按鈕添加了可編輯的輸入字段:
[CustomEditor(typeof(ActionContainer)), CanEditMultipleObjects]
public class CustomActionContainerInspector : Editor
{
private ActionContainer actionContainer;
public void OnEnable()
{
actionContainer = (ActionContainer)target;
}
public override void OnInspectorGUI()
{
actionContainer.OnInspectorGUI();
}
}
但是,在重新啟動 Unity 時,ScriptableObject 的內容消失了(程序集重建很好,播放/停止游戲也會保留數據)。
我嘗試向 BaseAction 添加一個字段來檢查這些值是否剛剛從繼承的 class 中剪掉,但沒有; ActionContainer 中的整個操作列表都清空了。
我相信序列化或反序列化列表本身的元素存在問題,因為它是多態的,但我不知道如何調試或解決問題; 互聯網搜索也沒有讓我找到解決方案。
首先,一般來說,您不應該調用您的方法OnGUI
,因為這也是MonoBehaviour
中的內置消息,可能會導致混淆。
我認為你的主要缺陷是骯臟的 state。
如果您在更改對象后沒有將它們標記為臟,那么您的更改將無法正確保存。
我認為對此的快速解決方法是使用EditorUtility.SetDirty
public override void OnGUI()
{
EditorGUI.BeginChangeCheck();
debugText = EditorGUILayout.TextField(debugText);
if(EditorGUI.EndChangeCheck())
{
EditorUtility.SetDirty(this);
}
}
或者如果您想正確支持撤消/重做,那么寧可使用Undo.RecordObject
public override void OnGUI()
{
EditorGUI.BeginChangeCheck();
var newDebugText = EditorGUILayout.TextField(debugText);
if(EditorGUI.EndChangeCheck())
{
Undo.RecordObject(this, "changed debug text");
debugText = newDebugText;
}
}
也可以看看
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.