【问题标题】:How to assign GameObject to child for serialization如何将游戏对象分配给孩子进行序列化
【发布时间】:2023-03-08 11:20:01
【问题描述】:

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

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

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

然后,在另一堂课上,我想有这样的东西:

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 的 GameObject。

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

作为参考,在以下链接中,此人从第 4 分钟到第 6 分钟都在这样做,但使用的是精灵而不是游戏对象。

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

【问题讨论】:

    标签: c# unity3d parent-child


    【解决方案1】:

    你可能是说

    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);
        }
    }
    

    然而,一般ScriptableObjects 是assetsGameObjects 是场景层次结构中的实例 -> 您不能简单地引用 assets 中的场景对象,无论如何这样做可能会导致意外行为。

    这是否有充分的理由必须在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
    }
    

    现在的样子

    【讨论】:

    • 这绝对解决了:)谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-07
    相关资源
    最近更新 更多