Unity 可编程对象根据另一个字段值将字段类型更改为新类型

2024-02-27

可编写脚本的对象是否可以具有特定类型的字段,并且可以根据另一个字段的类型来确定该类型?例如:

public class ItemObject : ScriptableObject
{
    public ItemType type;
    public Item data = new Item();
}

ItemType 是一个枚举

public enum ItemType 
{
    Physical,
    Magical
}

Item 是一个基本类,还有另外 2 个类继承自它,MagicalItem 和 PhysicalItem。

[System.Serializable]
public class MagicalItem : Item {
    public string passive; 

    public MagicalItem() {
        passive = "";
    }
}
ect.

我希望 ItemObject 能够在编辑器中从这些选项中进行选择,或者当我向游戏中添加新的项目类型时选择更多选项。我一直无法找到解决方案,但我的想法是根据类型在 Awake() 上设置数据类型,但我无法让它发挥作用。 IE 是这样的:

private void Awake() {
    if(type == ItemType.Magical) {
        data = new MagicalItem();
    } else {
        data = new PhysicalItem();
    }
}

有没有更好的方法来解决这个问题?

Thanks!


解决这个问题很有趣。

我发现的这个技巧实际上是一个新东西,[SerializeReference] https://docs.unity3d.com/ScriptReference/SerializeReference.html,它可以做一些事情,其中​​之一可以让您进行多态序列化,这是这个问题所需要的。

解决这个问题的主要步骤:

  • Add [SerializeReference] to the data field.
  • 添加一个静态方法,根据所需的类型创建新实例
  • 添加一个自定义编辑器来检查type字段进行更改,如果发生更改,则使用上述方法创建一个新实例并将其分配给data field

总而言之,这会给你这样的结果:

[CreateAssetMenu(fileName = "Data", menuName = "Inventory/Item", order = 1)]
public class ItemObject : ScriptableObject
{
    [CustomEditor(typeof(ItemObject))]
    public class ItemObjectInspector : Editor
    {
        SerializedProperty m_type;
        SerializedProperty m_data;

        private void OnEnable()
        {
            m_type = serializedObject.FindProperty("type");
            m_data = serializedObject.FindProperty("data");
        }

        public override void OnInspectorGUI()
        {
            serializedObject.Update();

            EditorGUI.BeginChangeCheck();
            EditorGUILayout.PropertyField(m_type);
            if (EditorGUI.EndChangeCheck())
            {
                m_data.managedReferenceValue = 
                        ItemObject.CreateBlankData((ItemType)m_type.intValue);
            }

            // avoid drawing type a second time
            // avoid drawing annoying Script field
            DrawPropertiesExcluding(serializedObject, new string[] { "type", "m_Script" });
            serializedObject.ApplyModifiedProperties();
        }
    }

    [System.Serializable]
    public enum ItemType
    {
        Physical,
        Magical
    }

    // Determines how to create an Item from each ItemType
    public static Item CreateBlankData(ItemType type)
    {
        switch (type)
        {
            default:
            case ItemType.Physical:
                return new PhysicalItem();

            case ItemType.Magical:
                return new MagicalItem();
        }
    }

    [System.Serializable]
    public class Item
    {
        [SerializeField] public string typeDescription;
    }

    [System.Serializable]
    public class MagicalItem : Item
    {
        [SerializeField] string elementName;

        public MagicalItem() { typeDescription = "Magical"; elementName = "fire"; }
    }

    [System.Serializable]
    public class PhysicalItem : Item
    {
        [SerializeField] float materialHardness;
        public PhysicalItem() { typeDescription = "Physical"; materialHardness = 1f; }

    }

    public ItemType type;
    [SerializeReference] public Item data;
}

注意:为了简洁起见,以上所有类都只是内部类。它们可以是单独的类或内部类,没有任何问题。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Unity 可编程对象根据另一个字段值将字段类型更改为新类型 的相关文章

随机推荐