如何将GameObject分配给child进行序列化

How to assign GameObject to child for serialization

我想为我创建的每个项目分配某种游戏对象,然后当我创建一个新的 object(称为项目)时,它将分配的游戏对象作为 child。

为此,我有一个 class 的可编写脚本的 object,其中包含一个名为“gameObj”的 public 游戏对象:

public abstract class ItemObject : ScriptableObject
{
    public int id;
    public GameObject gameObj;
}

然后,在另一个 class 我想要这样的东西:

public class GroundItem : MonoBehaviour, ISerializationCallbackReceiver
{
    public ItemObject item;

    public void OnBeforeSerialize()
    {
        this.gameObject.transform.GetChild(0) = item.gameObj; //WRONG CODE, NEED HELP HERE
    }
}

目的是将给定 ItemObject.item 的 gameObj 设置为 GroundItem 的游戏对象。

最终目的是拥有大量各种可编写脚本的物品(如面包、剑、石头等),每个物品都会分配一个游戏对象,一旦我创建了一个新的 GroundItem 游戏 object 我将简单地分配可编写脚本的 object 项目,它的 child 将拥有游戏 object 本身(包括所有视觉效果、特殊脚本等)。

供参考,在下面的 link 中,此人从第 4 分钟到第 6 分钟都在这样做,但使用的是精灵而不是游戏 object。

谁知道应该怎么写?有可能吗?

你可能是指

public class GroundItem : MonoBehaviour, ISerializationCallbackReceiver
{
    public ItemObject item;

    public void OnBeforeSerialize()
    {
        if(!item) return;
        if(!item.gameObj) return;

        // make according object a child of this object
        item.gameObj.transform.parent = transform;

        // make it the firs child
        item.gameObj.transform.SetSiblingIndex(0);
    }
}

但是,一般来说,ScriptableObject资产,GameObject是场景层次结构中的实例-> 您不能简单地引用资产中的场景对象,无论如何这样做可能会导致意外行为。

为什么必须在 ISerializationCallbackReceiver 中完成此操作是否有充分的理由?

我认为您实际上更想实现的是例如

public class GroundItem : MonoBehaviour
{
    public ItemObject item;

#if UNITY_EDITOR
    [HideInInspector]
    [SerializeField]
    private ItemObject _lastItem;

    // This is called whenever something is changed in this objects Inspector
    // like e.g. item ;)
    private void OnValidate()
    {
        // Delay the call in order to not get warnings for SendMessage
        UnityEditor.EditorApplication.delayCall += DelayedOnValidate;
    }

    private void DelayedOnValidate()
    {
        // remove the callback since we want to be sure it is always added only once
        UnityEditor.EditorApplication.delayCall -= DelayedOnValidate;

        // if item hasn't changed nothing to do
        if (item == _lastItem) return;

        // otherwise first destroy current child if any
        if (_lastItem && transform.childCount > 0)
        {
            if (Application.isPlaying) Destroy(transform.GetChild(0).gameObject);
            else DestroyImmediate(transform.GetChild(0).gameObject);
        }

        // is an item referenced and does it even have a gameObject ?
        if (item && item.gameObj)
        {
            // instantiate the new one as child of this object 
            var obj = Instantiate(item.gameObj, transform);

            // set as first child (if needed)
            obj.transform.SetSiblingIndex(0);

            if (!Application.isPlaying)
            {
                // if in edit mode mark this object as dirty so it needs to be saved
                UnityEditor.EditorUtility.SetDirty(gameObject);
                UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene());
            }
        }

        _lastItem = item;
    }
#endif
}

现在看起来像