Unity编辑器窗口列表一起展开

huangapple go评论70阅读模式
英文:

Unity Editor Window List expand together

问题

以下是您提供的代码的翻译部分:

// 此处是您的代码,不进行翻译
using UnityEngine;
using UnityEditor;
// 其他 using 语句...

public class ItemsLibraryEditor : EditorWindow
{
    // 其他成员变量...
    public List<Prop> _Properties;
    // 其他成员变量...

    [MenuItem("RPG/Items")]
    public static void ShowWindow()
    {
        EditorWindow.GetWindow<ItemsLibraryEditor>();
    }

    void OnEnable()
    {
        serializedObject = new SerializedObject(this);
        _Properties = new List<Prop>();
    }

    void OnGUI()
    {
        // 其他代码...
        EditorGUILayout.BeginHorizontal();
        if (currentType == ItemType.Weapon)
        {
            EditorGUILayout.LabelField("Properties:", GUILayout.Width(100));
            _Properties = new List<Prop>();
            _Properties = item.Properties;
            serializedObject.Update();
            SerializedProperty CustomInspectorVar = serializedObject.FindProperty("_Properties");
            EditorGUILayout.PropertyField(CustomInspectorVar, true);
            if (EditorGUI.EndChangeCheck()) serializedObject.ApplyModifiedProperties();
        }
        EditorGUILayout.EndHorizontal();
        // 其他代码...
    }

    // 其他方法...
}

public enum PropertyId // TODO: Set indexes.
{
    // 枚举项...
}

[Serializable]
public class Property
{
    public PropertyId Id;
    public string Value;
    // 其他字段和方法...
}

[CreateAssetMenu(fileName = "ItemCollection", menuName = "HeroEditor4D/ItemCollection")]
public class ItemCollection : ScriptableObject
{
    // 其他成员变量...
    public List<ItemParams> Items;
    // 其他成员变量...
}

public class ItemParams
{
    // 其他成员变量...
    public List<Property> Properties = new List<Property>();
    // 其他成员变量...
}

请注意,代码中的注释和变量名已保留为英文,只有代码本身进行了翻译。如果您有其他需要,请告诉我。

英文:

I am writing a custom editor window that will display items from a scriptable database. I have it mostly working. the Issue i have is that when I display the list<Property> for each item. They seem to be together. For example when I expand the list it expands all of them. Not sure what I'm missing.

using UnityEngine;
using UnityEditor;
using Assets.HeroEditor4D.InventorySystem.Scripts;
using Assets.HeroEditor4D.InventorySystem.Scripts.Data;
using Assets.HeroEditor4D.InventorySystem.Scripts.Enums;
using System.Collections.Generic;
using Unity.VisualScripting.ReorderableList;
using Prop = Assets.HeroEditor4D.InventorySystem.Scripts.Data.Property;

public class ItemsLibraryEditor : EditorWindow
{
    private ItemCollection library;
    private ItemType currentType;
    //Item.ItemTypes currentType = Item.ItemTypes.Quest;
    private Color defaultColor;
    private SerializedObject serializedObject;

    private Vector2 scrollPos;


    public List&lt;Prop&gt; _Properties;

    [MenuItem(&quot;RPG/Items&quot;)]
    public static void ShowWindow()
    {
        EditorWindow.GetWindow&lt;ItemsLibraryEditor&gt;();
    }

    void OnEnable() {
        serializedObject = new SerializedObject(this);
        _Properties = new List&lt;Prop&gt;();

    }

    void OnGUI()
    {
        defaultColor = GUI.backgroundColor;
        var collection = GameObject.Find(&quot;EquipmentManager&quot;).GetComponent&lt;EquipmentManager&gt;().ItemCollection;
        if(collection == null)
        {
            if (ItemCollection.Active == null) return;
            library = ItemCollection.Active;
        }
        else 
        {
            library = collection;
        }
        

        EditorGUILayout.BeginHorizontal();
        currentType = (ItemType)EditorGUILayout.EnumPopup(currentType);
        GUI.backgroundColor = Color.green;
        if (GUILayout.Button(&quot;Add&quot;)){
            ItemParams NewItem = new ItemParams();
            NewItem.Type = currentType;
             library.Items.Add(NewItem);
        }
        GUI.backgroundColor = defaultColor;
        EditorGUILayout.EndHorizontal();
        scrollPos = EditorGUILayout.BeginScrollView(scrollPos);
        for (int i = library.Items.Count - 1; i &gt;= 0; i--)
        {
            ItemParams item = library.Items[i];
            if (currentType == item.Type)
            {
                DrawCommonProperties(item);
                if (currentType == ItemType.Weapon) DrawWeaponProperties(item);
            }
        }
        EditorGUILayout.EndScrollView();
    }

    private void DrawCommonProperties(ItemParams item)
    {
        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField(&quot;ID&quot;, GUILayout.Width(20));
        item.Id = EditorGUILayout.TextField(item.Id, GUILayout.Width(180));
        EditorGUILayout.LabelField(&quot;Level:&quot;, GUILayout.Width(40));
        item.Level = EditorGUILayout.IntField(item.Level, GUILayout.Width(30));
        EditorGUILayout.LabelField(&quot;Name:&quot;, GUILayout.Width(40));
        item.DisplayName = EditorGUILayout.TextField(item.DisplayName, GUILayout.Width(160));
        EditorGUILayout.LabelField(&quot;Rarity: &quot;, GUILayout.Width(40));
        item.Rarity = (ItemRarity)EditorGUILayout.EnumPopup(item.Rarity, GUILayout.Width(120));
        EditorGUILayout.LabelField(&quot;Price:&quot;, GUILayout.Width(40));
        item.Price = EditorGUILayout.IntField(item.Price, GUILayout.Width(40));
        EditorGUILayout.LabelField(&quot;Icon:&quot;, GUILayout.Width(40));
        item.IconId = EditorGUILayout.TextField(item.IconId, GUILayout.Width(300));
        EditorGUILayout.LabelField(&quot;Sprite:&quot;, GUILayout.Width(40));
        item.SpriteId = EditorGUILayout.TextField(item.SpriteId, GUILayout.Width(300));
        //EditorGUILayout.LabelField(&quot;Icon&quot;, GUILayout.Width(50));
        //item.Params.Properties = EditorGUILayout.li
        //(Sprite)EditorGUILayout.ObjectField(item.icon, typeof(Sprite), false, GUILayout.Width(120));

        GUI.backgroundColor = Color.red;
        if (GUILayout.Button(&quot;Remove&quot;, GUILayout.Width(120))) library.Items.Remove(item);
        GUI.backgroundColor = defaultColor;
        EditorGUILayout.EndHorizontal();
    }

    private void DrawWeaponProperties(ItemParams item)
    {
        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField(&quot;Damage Type: &quot;, GUILayout.Width(100));
        item.damageType = (DamageType)EditorGUILayout.EnumPopup(item.damageType, GUILayout.Width(70));
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        if (currentType == ItemType.Weapon)
        {
            EditorGUILayout.LabelField(&quot;Properties:&quot;, GUILayout.Width(100));
            _Properties = new List&lt;Prop&gt;();
            _Properties = item.Properties;
            //ReorderableListGUI.ListField(_Properties, DrawListItem);
            //ReorderableListGUI.ListField(_properties, DrawListItem);
            serializedObject.Update();
            SerializedProperty CustomInspectorVar = serializedObject.FindProperty(&quot;_Properties&quot;);
            EditorGUILayout.PropertyField(CustomInspectorVar, true);
            if(EditorGUI.EndChangeCheck()) serializedObject.ApplyModifiedProperties();  
            //ReorderableListGUI.ListField(_Properties, GUILayout.Height(100));
        }
        //_Properties = item.Properties;
        //serializedObject = new SerializedObject(this); 
        /*serializedObject.Update();
        
        SerializedProperty CustomInspectorVar = serializedObject.FindProperty(&quot;_Properties&quot;);
        EditorGUILayout.PropertyField(CustomInspectorVar, true);

        if(EditorGUI.EndChangeCheck()) serializedObject.ApplyModifiedProperties(); 
        */
        //ReorderableListGUI.ListField(_Properties, DrawListItem);
        //item.Properties.Add(new Property(PropertyId.Damage,value));
        EditorGUILayout.EndHorizontal();
    }

    private void DrawListItem(Rect rect, int index, bool isActive, bool isFocused)
    {
        Assets.HeroEditor4D.InventorySystem.Scripts.Data.Property property = _Properties[index];
        EditorGUI.LabelField(rect, property.Id.ToString());
    }

}

Property Class (stripped down)

using System;
using System.Runtime.Serialization;
using System.Text.RegularExpressions;
using Assets.HeroEditor4D.Common.Scripts.Common;
using Assets.HeroEditor4D.InventorySystem.Scripts.Enums;
using UnityEngine;

namespace Assets.HeroEditor4D.InventorySystem.Scripts.Data
{

public enum PropertyId // TODO: Set indexes.
    {
        Accuracy,
        Ammo,
        Antidote,
        Bandage,
        Blocking,
        BlockingFatigue,
        Capacity,
        ChargeSpeed,
        ChargeTimings,
        Craft,
        CriticalChance,
        CriticalDamage,
        CustomPrice,
        Damage,
        Duration,
        Effect,
        Exp,
        Fatigue,
        Gunpowder,
        HealthRecovery,
        HealthRestore,
        HealthMax,
        Immunity,
        Magazine,
        Materials,
        Mechanism,
        Radius,
        Range,
        Reloading,
        Resistance,
        ShopChance,
        SkillUp,
        Speed,
        StaminaRecovery,
        StaminaRestore,
        StaminaMax,
        Shock,
        Contains,
        DamageBonus,
        Multishot,
        Fragments,
        DropChance,
        ExpBonus,
        GoldBonus
    }
    /// &lt;summary&gt;
    /// Represents key-value pair for storing item params.
    /// &lt;/summary&gt;
    [Serializable]
    public class Property
    {
        public PropertyId Id;
        public string Value;
        // NonSerialized
        [HideInInspector][NonSerialized] public int ValueInt;
        [HideInInspector] [NonSerialized] public int Min;
        [HideInInspector] [NonSerialized] public int Max;
        [HideInInspector] [NonSerialized] public int Duration;
        [HideInInspector] [NonSerialized] public bool Percentage;

        public Property()
        {
        }

        public Property(PropertyId id, object value)
        {
            Id = id;
            Value = value.ToString();
        }

        
}

other Types

using System;
using System.Collections.Generic;
using System.Linq;

using UnityEngine;

    [CreateAssetMenu(fileName = &quot;ItemCollection&quot;, menuName = &quot;HeroEditor4D/ItemCollection&quot;)]
    public class ItemCollection : ScriptableObject
    {
        [Header(&quot;Main&quot;)]
        public List&lt;ItemParams&gt; Items;

        [Header(&quot;Extra&quot;)]
        public Sprite BackgroundBlue;
        public Sprite BackgroundBrown;
        public Sprite BackgroundGreen;
        public Sprite BackgroundGrey;
        public Sprite BackgroundPurple;
        public Sprite BackgroundRed;

        public static ItemCollection Active;

    }
	
	public class ItemParams
    {
	    public string Id;
        public int Level = 1;
        public string DisplayName;
        public ItemRarity Rarity; //enum Field
        public ItemType Type; //enum Field
        [SerializeField]
        public List&lt;ItemTag&gt; Tags = new List&lt;ItemTag&gt;();
        [SerializeField]
        public List&lt;Property&gt; Properties = new List&lt;Property&gt;();
        public DamageType damageType;
        public int Price;
        public string IconId;
        public string SpriteId;
}

Here is a screenshot of what I have so far.

Unity编辑器窗口列表一起展开

I am currently using ProperyField which seems to be working. I tried changing them to reorderedlist (see committed lines) but I couldn't get it to display them.

EDIT
after derHugo update. everything working except the list will not expand items.
enter image description here

答案1

得分: 0

以下是您提供的代码的翻译部分:

两个列表同时展开和折叠的主要原因是它们都是编辑器窗口的相同属性“_Properties”的绘图。

通常情况下,我宁愿使用此编辑器本身的本地“serializedObject”而是使用以下方式:

```csharp
var serializedObject = new SerializedObject(library);

并通过该方式访问相应的属性。

public class ItemsLibraryEditor : EditorWindow
{
    private ItemType currentType;
    private Vector2 scrollPos;
    private ItemCollection library;

    [MenuItem("RPG/Items")]
    public static void ShowWindow()
    {
        GetWindow<ItemsLibraryEditor>();
    }

    private static ItemCollection GetItemCollection()
    {
        var collection = FindObjectOfType<EquipmentManager>().ItemCollection;

        if (collection != null)
        {
            return collection;
        }

        return ItemCollection.Active == null ? null : ItemCollection.Active;
    }

    private void DrawScriptField()
    {
        using (new EditorGUI.DisabledScope(true))
        {
            EditorGUILayout.ObjectField("Script", MonoScript.FromScriptableObject(this), typeof(MonoScript), false);
        }

        EditorGUILayout.Space();
    }

    private void OnGUI()
    {
        DrawScriptField();

        library = GetItemCollection();

        if (library == null)
        {
            EditorGUILayout.HelpBox($"找不到{nameof(ItemCollection)}的活动实例!", MessageType.Error);
            return;
        }

        using (new EditorGUILayout.HorizontalScope())
        {
            currentType = (ItemType)EditorGUILayout.EnumPopup(currentType);

            var defaultColor = GUI.backgroundColor;
            GUI.backgroundColor = Color.green;

            if (GUILayout.Button("添加"))
            {
                var newItem = new ItemParams
                {
                    Type = currentType
                };

                Undo.RecordObject(library, "添加新项目");
                library.Items.Add(newItem);
                EditorUtility.SetDirty(library);
            }

            GUI.backgroundColor = defaultColor;
        }

        var serializedObject = new SerializedObject(library);

        serializedObject.Update();

        var itemsProperty = serializedObject.FindProperty(nameof(ItemCollection.Items));

        using (var scrollView = new EditorGUILayout.ScrollViewScope(scrollPos))
        {
            scrollPos = scrollView.scrollPosition;

            for (var i = itemsProperty.arraySize - 1; i >= 0; i--)
            {
                var item = itemsProperty.GetArrayElementAtIndex(i);
                if (item.FindPropertyRelative(nameof(ItemParams.Type)).intValue == (int)currentType)
                {
                    DrawCommonProperties(item, i);
                    if (currentType == ItemType.Weapon) DrawWeaponProperties(item);
                }
            }
        }

        serializedObject.ApplyModifiedProperties();
    }

    private void DrawCommonProperties(SerializedProperty item, int index)
    {
        using (new EditorGUILayout.HorizontalScope())
        {
            EditorGUILayout.LabelField("ID", GUILayout.Width(20));
            EditorGUILayout.PropertyField(item.FindPropertyRelative(nameof(ItemParams.Id)), GUIContent.none, GUILayout.Width(180));

            EditorGUILayout.LabelField("Level:", GUILayout.Width(40));
            EditorGUILayout.PropertyField(item.FindPropertyRelative(nameof(ItemParams.Level)), GUIContent.none, GUILayout.Width(30));

            EditorGUILayout.LabelField("Name:", GUILayout.Width(40));
            EditorGUILayout.PropertyField(item.FindPropertyRelative(nameof(ItemParams.DisplayName)), GUIContent.none, GUILayout.Width(160));

            EditorGUILayout.LabelField("Rarity: ", GUILayout.Width(40));
            EditorGUILayout.PropertyField(item.FindPropertyRelative(nameof(ItemParams.Rarity)), GUIContent.none, GUILayout.Width(120));

            EditorGUILayout.LabelField("Price:", GUILayout.Width(40));
            EditorGUILayout.PropertyField(item.FindPropertyRelative(nameof(ItemParams.Price)), GUIContent.none, GUILayout.Width(40));

            EditorGUILayout.LabelField("Icon:", GUILayout.Width(40));
            EditorGUILayout.PropertyField(item.FindPropertyRelative(nameof(ItemParams.IconId)), GUIContent.none, GUILayout.Width(300));

            EditorGUILayout.LabelField("Sprite:", GUILayout.Width(40));
            EditorGUILayout.PropertyField(item.FindPropertyRelative(nameof(ItemParams.SpriteId)), GUIContent.none, GUILayout.Width(300));

            var defaultColor = GUI.backgroundColor;
            GUI.backgroundColor = Color.red;
            if (GUILayout.Button("删除", GUILayout.Width(120)))
            {
                Undo.RecordObject(library, "删除项目");
                library.Items.RemoveAt(index);
                EditorUtility.SetDirty(library);
            }

            GUI.backgroundColor = defaultColor;
        }
    }

    private void DrawWeaponProperties(SerializedProperty item)
    {
        using (new EditorGUILayout.HorizontalScope())
        {
            EditorGUILayout.LabelField("伤害类型: ", GUILayout.Width(100));
            EditorGUILayout.PropertyField(item.FindPropertyRelative(nameof(ItemParams.damageType)), GUIContent.none, GUILayout.Width(70));
        }

        using (new EditorGUILayout.HorizontalScope())
        {
            if (currentType == ItemType.Weapon)
            {
                EditorGUILayout.LabelField("属性:", GUILayout.Width(100));

                var customInspectorVar = item.FindPropertyRelative(nameof(ItemParams.Properties));
                EditorGUILayout.PropertyField(customInspectorVar, GUIContent.none, true);
            }
        }
    }
}

希望这有所帮助!

英文:

The main reason why both lists fold and unfold together is because they are both drawings of the exact same property _Properties of your editor window.

In general instead of using this local serializedObject of your editor itself, I would rather use and go through

var serializedObject = new SerializedObject(library);

instead and access according properties through that one.

public class ItemsLibraryEditor : EditorWindow
{
private ItemType currentType;
private Vector2 scrollPos;
private ItemCollection library;
[MenuItem(&quot;RPG/Items&quot;)]
public static void ShowWindow()
{
GetWindow&lt;ItemsLibraryEditor&gt;();
}
private static ItemCollection GetItemCollection()
{
var collection = FindObjectOfType&lt;EquipmentManager&gt;().ItemCollection;
if (collection != null)
{
return collection;
}
return ItemCollection.Active == null ? null : ItemCollection.Active;
}
private void DrawScriptField()
{
using (new EditorGUI.DisabledScope(true))
{
EditorGUILayout.ObjectField(&quot;Script&quot;, MonoScript.FromScriptableObject(this), typeof(MonoScript), false);
}
EditorGUILayout.Space();
}
private void OnGUI()
{
DrawScriptField();
library = GetItemCollection();
if (library == null)
{
EditorGUILayout.HelpBox($&quot;Could not find active instance of {nameof(ItemCollection)}!&quot;, MessageType.Error);
return;
}
using (new EditorGUILayout.HorizontalScope())
{
currentType = (ItemType)EditorGUILayout.EnumPopup(currentType);
var defaultColor = GUI.backgroundColor;
GUI.backgroundColor = Color.green;
if (GUILayout.Button(&quot;Add&quot;))
{
var newItem = new ItemParams
{
Type = currentType
};
Undo.RecordObject(library, &quot;Added new item&quot;);
library.Items.Add(newItem);
EditorUtility.SetDirty(library);
}
GUI.backgroundColor = defaultColor;
}
var serializedObject = new SerializedObject(library);
serializedObject.Update();
var itemsProperty = serializedObject.FindProperty(nameof(ItemCollection.Items));
using (var scrollView = new EditorGUILayout.ScrollViewScope(scrollPos))
{
scrollPos = scrollView.scrollPosition;
for (var i = itemsProperty.arraySize - 1; i &gt;= 0; i--)
{
var item = itemsProperty.GetArrayElementAtIndex(i);
if (item.FindPropertyRelative(nameof(ItemParams.Type)).intValue == (int)currentType)
{
DrawCommonProperties(item, i);
if (currentType == ItemType.Weapon) DrawWeaponProperties(item);
}
}
}
serializedObject.ApplyModifiedProperties();
}
private void DrawCommonProperties(SerializedProperty item, int index)
{
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.LabelField(&quot;ID&quot;, GUILayout.Width(20));
EditorGUILayout.PropertyField(item.FindPropertyRelative(nameof(ItemParams.Id)), GUIContent.none, GUILayout.Width(180));
EditorGUILayout.LabelField(&quot;Level:&quot;, GUILayout.Width(40));
EditorGUILayout.PropertyField(item.FindPropertyRelative(nameof(ItemParams.Level)), GUIContent.none, GUILayout.Width(30));
EditorGUILayout.LabelField(&quot;Name:&quot;, GUILayout.Width(40));
EditorGUILayout.PropertyField(item.FindPropertyRelative(nameof(ItemParams.DisplayName)), GUIContent.none, GUILayout.Width(160));
EditorGUILayout.LabelField(&quot;Rarity: &quot;, GUILayout.Width(40));
EditorGUILayout.PropertyField(item.FindPropertyRelative(nameof(ItemParams.Rarity)), GUIContent.none, GUILayout.Width(120));
EditorGUILayout.LabelField(&quot;Price:&quot;, GUILayout.Width(40));
EditorGUILayout.PropertyField(item.FindPropertyRelative(nameof(ItemParams.Price)), GUIContent.none, GUILayout.Width(40));
EditorGUILayout.LabelField(&quot;Icon:&quot;, GUILayout.Width(40));
EditorGUILayout.PropertyField(item.FindPropertyRelative(nameof(ItemParams.IconId)), GUIContent.none, GUILayout.Width(300));
EditorGUILayout.LabelField(&quot;Sprite:&quot;, GUILayout.Width(40));
EditorGUILayout.PropertyField(item.FindPropertyRelative(nameof(ItemParams.SpriteId)), GUIContent.none, GUILayout.Width(300));
var defaultColor = GUI.backgroundColor;
GUI.backgroundColor = Color.red;
if (GUILayout.Button(&quot;Remove&quot;, GUILayout.Width(120)))
{
Undo.RecordObject(library, &quot;Removed item&quot;);
library.Items.RemoveAt(index);
EditorUtility.SetDirty(library);
}
GUI.backgroundColor = defaultColor;
}
}
private void DrawWeaponProperties(SerializedProperty item)
{
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.LabelField(&quot;Damage Type: &quot;, GUILayout.Width(100));
EditorGUILayout.PropertyField(item.FindPropertyRelative(nameof(ItemParams.damageType)), GUIContent.none, GUILayout.Width(70));
}
using (new EditorGUILayout.HorizontalScope())
{
if (currentType == ItemType.Weapon)
{
EditorGUILayout.LabelField(&quot;Properties:&quot;, GUILayout.Width(100));
var customInspectorVar = item.FindPropertyRelative(nameof(ItemParams.Properties));
EditorGUILayout.PropertyField(customInspectorVar, GUIContent.none, true);
}
}
}
}

huangapple
  • 本文由 发表于 2023年7月10日 20:11:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/76653605.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定