Unity Inspector中为PlayerClass创建护甲集下拉列表
问题
我是C#新手,正在自学并借助教程开发背包系统。我使用ScriptableObject按套装存储所有护甲,现在需要在PlayerClass ScriptableObject的Inspector面板中,为不同职业设置默认护甲时,能从Armor脚本中已创建的护甲列表选择(即让startingArmorSet变为下拉列表)。
我的Armor Collection代码:
public class ArmorCollection : ScriptableObject { [System.Serializable] private class ArmorSet { public string armorSetName; //gear sprites and stats are below this in this nested class } [SerializeField] List<ArmorSet> armorSet; private Dictionary<int, string> setName; //not sure if it should be a List or Dictionary currently [HideInInspector] public Dictionary<int, string> SetName { get => setName; } private void OnValidate() { for (int i = 0; i < armorSet.Count; i++) { setName.Add(i+1,armorSet[i].armorSetName); } } }
我的Player Class脚本当前卡在这部分:
public class PlayerClass : ScriptableObject { [SerializeField] PlayerStats playerData; [SerializeField] PlayerGear gear; [SerializeField] ArmorCollection armor; [Space] [SerializeField] string className; [Header("Gear")] [SerializeField] string startingArmorSet; //needs to be a dropdown list }
我曾考虑用枚举,但枚举是只读的,不符合需求。我需要能根据不同ScriptableObject(默认职业护甲、普通护甲、稀有护甲等)动态变更下拉选项,目前纠结setName用List还是Dictionary,不知道如何在PlayerClass脚本中实现下拉列表功能,求帮助。
解决方案
1. 重构ArmorCollection逻辑
放弃Dictionary,改用List存储护甲套装名称更适配动态下拉需求,同时修复OnValidate的空引用问题:
public class ArmorCollection : ScriptableObject { [System.Serializable] private class ArmorSet { public string armorSetName; // 保留原有装备精灵、属性等字段 } [SerializeField] private List<ArmorSet> armorSets; [HideInInspector] public List<string> ArmorSetNames { get; private set; } private void OnValidate() { ArmorSetNames = new List<string>(); foreach (var set in armorSets) { if (!string.IsNullOrEmpty(set.armorSetName)) { ArmorSetNames.Add(set.armorSetName); } } } }
- 把
armorSet改为armorSets(命名更规范) - 用
List<string>存储套装名称,每次OnValidate触发时重新生成列表,避免重复添加的错误
2. 编写自定义Inspector下拉扩展
要实现动态下拉,需要创建两个脚本(放在Editor文件夹下,否则无法识别为编辑器扩展):
第一步:创建属性标记类
using UnityEngine; public class ArmorSetDropdownAttribute : PropertyAttribute { }
第二步:创建PropertyDrawer实现下拉逻辑
using UnityEditor; using UnityEngine; [CustomPropertyDrawer(typeof(ArmorSetDropdownAttribute))] public class ArmorSetDropdownDrawer : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { var playerClass = property.serializedObject.targetObject as PlayerClass; if (playerClass == null || playerClass.armor == null) { EditorGUI.PropertyField(position, property, label); return; } var armorNames = playerClass.armor.ArmorSetNames; if (armorNames == null || armorNames.Count == 0) { EditorGUI.PropertyField(position, property, label); return; } int selectedIndex = armorNames.IndexOf(property.stringValue); selectedIndex = selectedIndex < 0 ? 0 : selectedIndex; selectedIndex = EditorGUI.Popup(position, label, selectedIndex, armorNames.ToArray()); property.stringValue = armorNames[selectedIndex]; } }
3. 修改PlayerClass脚本
给startingArmorSet添加自定义属性标记,启用下拉功能:
public class PlayerClass : ScriptableObject { [SerializeField] PlayerStats playerData; [SerializeField] PlayerGear gear; [SerializeField] ArmorCollection armor; [Space] [SerializeField] string className; [Header("Gear")] [ArmorSetDropdown] // 新增标记 [SerializeField] string startingArmorSet; }
关键注意点
- 所有Editor脚本必须放在项目的
Editor文件夹内,Unity才会将其识别为编辑器扩展代码 - 确保ArmorCollection中的护甲套装名称唯一,否则下拉框会选中第一个匹配项
- 当你修改ArmorCollection中的护甲套装时,PlayerClass的Inspector会自动刷新下拉选项(OnValidate触发更新)
内容的提问来源于stack exchange,提问作者Kristine
相关产品推荐
相关产品推荐

