简体   繁体   English

Unity自定义检查器,允许选定的子对象

[英]Unity custom inspector which allows selected child objects

I'm trying to make a custom inspector for a PlayerInventory class. 我正在尝试为PlayerInventory类创建自定义检查器。 The PlayerInventory class consists of a list of items (which are ScriptableObjects ), along with a quantity of each item, like this: 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;
}

I created an instance of PlayerInventory as a game asset. 我创建了一个PlayerInventory实例作为游戏资产。 By default, the Inspector shows a list of InventoryItem s. 默认情况下,Inspector显示InventoryItem列表。 However, what I want is for the Inspector to show each InventoryItem element with a field to select an Item for it, a field to enter a quantity, and a "delete" button. 但是,我想要的是Inspector为每个InventoryItem元素显示一个字段来为它选择一个Item ,一个输入数量的字段和一个“删除”按钮。

Here's a visual example of what I'm trying to achieve, along with my current code below. 这是我正在尝试实现的一个直观示例,以及下面的当前代码。 The problem with this screenshot is that Unity is making me select an InventoryItem object for each element. 这个屏幕截图的问题是Unity让我为每个元素选择一个InventoryItem对象。 I want to be able to select an Item object for each element. 我希望能够为每个元素选择一个Item对象。 The second problem I'm having is I don't know how to set an EditorGUILayout.TextField to the InventoryItem.quantity property because I don't know how to convert the SerializedProperty to an InventoryItem object. 我遇到的第二个问题是我不知道如何将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");
   }
}

Classes must be serializable to appear in the Inspector. 类必须可序列化以显示在Inspector中。 See Serializable 请参见Serializable

Edit . 编辑 Following further discussion in the comments below, here's the full snippet; 在下面的评论中进一步讨论后,这里是完整的片段;

Standard class marked Serializable ; 标准类标记为Serializable ;

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

With PlayerInventoryEditor; 使用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");
}

You can use FindPropertyRelative 您可以使用FindPropertyRelative

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

And same method for your 'Quantity' field. 和“数量”字段的方法相同。

Make sure InventoryItem not null in your items List. 确保您的商品列表中的InventoryItem不为null

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM