【问题标题】:Unity custom inspector which allows selected child objectsUnity 自定义检查器,允许选定的子对象
【发布时间】:2018-03-27 00:35:47
【问题描述】:

我正在尝试为 PlayerInventory 类创建自定义检查器。 PlayerInventory 类由项目列表(ScriptableObjects)以及每个项目的数量组成,如下所示:

public class Item : ScriptableObject
{
   public string description;
   public Sprite picture;
}

public class InventoryItem : ScriptableObject
{
   // A reference to the Item object that contains the item's description, 
   // picture, stats, etc.
   public Item item;

   // The quantity of this item that the player has in his inventory
   public int quantity;
}

[CreateAssetMenu(menuName = "Player/Player Inventory")]
public class PlayerInventory : ScriptableObject
{
   // The list of each distinct item that the player has in his inventory,
   // along with the quantity of each item
   public List<InventoryItem> items;
}

我创建了一个PlayerInventory 的实例作为游戏资产。默认情况下,检查器显示InventoryItems 的列表。但是,我想要检查器显示每个 InventoryItem 元素,其中包含一个字段以为其选择 Item、一个字段用于输入数量和一个“删除”按钮。

下面是我想要实现的目标的可视化示例,以及下面我当前的代码。这个屏幕截图的问题是 Unity 让我为每个元素选择一个 InventoryItem 对象。我希望能够为每个元素选择一个 Item 对象。我遇到的第二个问题是我不知道如何将EditorGUILayout.TextField 设置为InventoryItem.quantity 属性,因为我不知道如何将SerializedProperty 转换为InventoryItem 对象。

[CustomEditor(typeof(PlayerInventory))]
public class PlayerInventoryEditor : Editor
{
   public override void OnInspectorGUI()
   {
       this.serializedObject.Update();

       SerializedProperty items = this.serializedObject.FindProperty("items");
       for (int i = 0; i < items.arraySize; i++)
       {
           EditorGUILayout.BeginHorizontal();
           EditorGUILayout.LabelField("Item", GUILayout.Width(50));

           // I don't know how to make this line reference the child "item"
           // field of the current InventoryItem
           EditorGUILayout.PropertyField(items.GetArrayElementAtIndex(i), GUIContent.none, GUILayout.Width(170));

           EditorGUILayout.LabelField("    Quantity", GUILayout.Width(80));

           // I don't know how to set the text field to the "quantity" field
           // of the current InventoryItem
           EditorGUILayout.TextField("0", GUILayout.Width(50));

           EditorGUILayout.LabelField("", GUILayout.Width(20));
           GUILayout.Button("Delete Item");               
           EditorGUILayout.EndHorizontal();
       }

       GUILayout.Button("Add Item");
   }
}

【问题讨论】:

  • 我尝试让 InventoryItem 现在继承自 ScriptableObject,现在 Inspector 可以像我期望的那样工作,并让我显示 item 字段。 ScriptableObject 是什么导致检查员的工作方式不同?

标签: c# unity3d


【解决方案1】:

类必须可序列化才能出现在 Inspector 中。见Serializable

编辑。在下面的 cmets 中进一步讨论后,这里是完整的 sn-p;

标有Serializable的标准类;

[System.Serializable]
public class InventoryItem
{
    public Item item;
    public int quantity;
}

使用 PlayerInventoryEditor;

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

    SerializedProperty items = this.serializedObject.FindProperty("items");

    for (int i = 0; i < items.arraySize; i++)
    {
        SerializedProperty item = items.GetArrayElementAtIndex(i);

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Item", GUILayout.Width(50));
        EditorGUILayout.PropertyField(item.FindPropertyRelative("item"), GUIContent.none, GUILayout.Width(170));
        EditorGUILayout.LabelField("    Quantity", GUILayout.Width(80));
        EditorGUILayout.IntField(item.FindPropertyRelative("quantity").intValue, GUILayout.Width(50));

        EditorGUILayout.LabelField("", GUILayout.Width(20));
        GUILayout.Button("Delete Item");
        EditorGUILayout.EndHorizontal();
    }

    GUILayout.Button("Add Item");
}

【讨论】:

  • ScriptableObjects 默认不是可序列化的吗?
  • 是的,Unity 对象默认是可序列化的。根据我的回答,您的原始代码没有覆盖ScriptableObject 并且没有标记为serializable,这就是导致原始问题的原因。 (抱歉,阅读您的问题和发送答案之间存在延迟,所以我错过了编辑):)
  • 对那个编辑感到抱歉。我正在将我的代码输入到帖子中,但我忘记将来自ScriptableObject 的继承放在那里。似乎从 ScriptableObject 继承会导致 Inspector 的行为与类只是可序列化而不是从 ScriptableObject 继承时不同
  • 没问题 Ben - 我没有再次检查问题是我的错。 :)
  • Inspector 的行为有所不同,因为标准类(不是从 MonoBehaviour/ScriptableObject 继承的)没有像 SO 资产文件这样的默认属性字段。尽管如此,就功能而言,它与标记为serializable 的标准类同样适用,就像它与从SO 继承的类一样。我已经检查了这个是否健全,似乎是这样。由于我已经输入了它(并且无意复制@nipercop的出色答案),我将更新我的答案以确保完整性/清晰......
【解决方案2】:

您可以使用FindPropertyRelative

//...
EditorGUILayout.PropertyField(
    items.GetArrayElementAtIndex(i).FindPropertyRelative("item"),
    new GUIContent("Item"), 
    GUILayout.Width(170));
//...

“数量”字段的方法相同。

确保您的商品列表中的 InventoryItem 不是 null

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-02
    • 1970-01-01
    • 2020-12-15
    • 1970-01-01
    相关资源
    最近更新 更多