簡體   English   中英

unity ScriptableObject 多態 Arrays 序列化

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM