目標:從專案視圖創建嵌套的可撰寫腳本的物件。
預期:當從專案視圖創建容器可撰寫腳本物件的實體時,將創建子可撰寫腳本物件的實體并將其附加到容器資產。容器還應該保留孩子的參考。
實際:當我嘗試將孩子附加到容器資產時,它失敗了。我使用AssetDatabase.AddObjectToAsset但給了我以下錯誤訊息:
- UnityException:將資產添加到物件失敗。
- AddAssetToSameFile 失敗,因為其他資產不是持久的
觀察結果:容器創建成功。不創建子資產。一旦創建資產,檢查器就會顯示子參考,但Type mismatch會在輸入容器名稱時顯示。
子物件不是持久的。我不知道在這種情況下持久是什么意思。我想這可能是我不明白這個問題的原因。
以下是我正在嘗試實作的簡化版本的代碼。重現相同的錯誤。
容器類
[CreateAssetMenu]
public class Container : ScriptableObject
{
[SerializeField] private Child child;
private void Reset()
{
// Create new child
child = ScriptableObject.CreateInstance<Child>();
// Attach child to the container
AssetDatabase.AddObjectToAsset(child, this); // This line throws exception!
// Save changes
AssetDatabase.SaveAssets();
}
}
兒童班
public class Child : ScriptableObject
{
[SerializeField] public string myString;
}
uj5u.com熱心網友回復:
問題是,在您輸入名稱之前,新創建的 scriptableObject 還沒有持久化。如果你點擊 Escape 那么它永遠不會被創建;)
您可以做的是將子創建延遲到實際創建資產為止。為了檢查這一點,您可以使用AssetDatabase.Contains
但請注意:我建議不僅依賴Reset而且還使用OnValidateandAwake以便在有人通過 Inspector 更改它時強制設定孩子。在這種情況下,我會簡單地檢查該資產中是否已經存在一個孩子,以免重新創建它。
另請注意:UnityEditor在構建中完全被剝離!
=> 如果這是用于 Unity 編輯器本身之外的運行時應用程式,請確保將與UnityEditor前處理器標簽相關的任何內容包裝起來
#if UNITY_EDITOR
any code related to UnityEditor namespace
#endif
所以我會做類似的事情
using System;
using System.Linq;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
[CreateAssetMenu]
public class Container : ScriptableObject
{
[SerializeField]
private Child child;
#if UNITY_EDITOR
private void Awake()
{
Init();
}
private void OnValidate()
{
Init();
}
private void Reset()
{
Init();
}
private void OnDestroy()
{
EditorApplication.update -= DelayedInit;
}
private void Init()
{
// If child is already set -> nothing to do
if (child)
{
return;
}
// If this asset already exists initialize immediately
if (AssetDatabase.Contains(this))
{
DelayedInit();
}
// otherwise attach a callback to the editor update to re-check repeatedly until it exists
// this means it is currently being created an the name has not been confirmed yet
else
{
EditorApplication.update -= DelayedInit;
EditorApplication.update = DelayedInit;
}
}
private void DelayedInit()
{
// if this asset dos still not exist do nothing
// this means it is currently being created and the name not confirmed yet
if (!AssetDatabase.Contains(this))
{
return;
}
// as soon as the asset exists remove the callback as we don't need it anymore
EditorApplication.update -= DelayedInit;
// first try to find existing child within all assets contained in this asset
var assets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(this));
// you could as well use a loop but this Linq query is a shortcut for finding the first sub asset
// of type "Child" or "null" if there was none
child = assets.FirstOrDefault(a => a.GetType() == typeof(Child)) as Child;
// did we find a child ?
if (!child)
{
// If not create a new child
child = CreateInstance<Child>();
// just for convenience I'd always give assets a meaningful name
child.name = name "_Child";
// Attach child to the container
AssetDatabase.AddObjectToAsset(child, this);
}
// Mark this asset as dirty so it is correctly saved in case we just changed the "child" field
// without using the "AddObjectToAsset" (which afaik does this automatically)
EditorUtility.SetDirty(this);
// Save all changes
AssetDatabase.SaveAssets();
}
#endif
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/432317.html
標籤:C# unity3d 统一编辑 unity3d 编辑器
上一篇:如何將兩個字串字典發送到服務器?
