跳到主要内容

2. 创建配置编辑器

现在我们需要为上一章定义的 CharacterConfig 创建对应的编辑器。

我们创建名为 "CharacterConfigEditor" 的编辑器类, 并从 winS.UnityEditor.ConfigManagement.ConfigsEditor 继承:

CharacterConfigEditor.cs
using UnityEngine.UIElements;
using winS.UnityEditor.ConfigManagement;

public class CharacterConfigEditor : ConfigsEditor<CharacterConfig>
{
protected override string directory { get; }

protected override void OnConfigLoaded(CharacterConfig config)
{
throw new System.NotImplementedException();
}

protected override void OnCreateGUI(VisualElement content)
{
throw new System.NotImplementedException();
}
}

通过上述代码可以看到,winS.UnityEditor.ConfigManagement.ConfigsEditor 要求子类实现:

  • directory 表明配置文件储存的目录(基于项目目录)。
  • OnConfigLoaded 当前编辑的配置文件变动时的回调。
  • OnCreateGUI 在此处创建您的配置文件的GUI。

我们简单实现此编辑器,代码如下:

CharacterConfigEditor.cs
using UnityEditor;
using UnityEngine.UIElements;
using winS.UnityEditor.ConfigManagement;
using winS.UnityEditor.GUI;
using winS.UnityEditor.UIElement;
using static CharacterConfig;
using FloatField = winS.UnityEditor.UIElement.FloatField;
using Slider = winS.UnityEditor.UIElement.Slider;
using TextField = winS.UnityEditor.UIElement.TextField;
using Toggle = winS.UnityEditor.UIElement.Toggle;

public sealed class CharacterConfigEditor : ConfigsEditor<CharacterConfig>
{
protected override string directory => "Assets/Configs/CharacterConfig";

private Toggle botToggle;
private IntField hpField;
private IntField mpField;
private TextField nameField;
private FloatField attackField;
private FloatField defenseField;
private Slider criticalSlider;
private EnumField<ProfessionType> professionField;

private ListView<string> skillListView;

[MenuItem("Example/Window/Character Config Editor")]
private static void Open()
{
GetWindow<CharacterConfigEditor>("Character Config Editor");
}

protected override void OnConfigLoaded(CharacterConfig config)
{
hpField.SetValueWithoutNotify(config.hp);
mpField.SetValueWithoutNotify(config.mp);
botToggle.SetValueWithoutNotify(config.bot);
nameField.SetValueWithoutNotify(config.name);
attackField.SetValueWithoutNotify(config.attack);
defenseField.SetValueWithoutNotify(config.defense);
criticalSlider.SetValueWithoutNotify(config.critical);
professionField.SetValueWithoutNotify(config.professionType);
skillListView.SetData(config.skillNameList);
}

protected override void OnCreateGUI(VisualElement content)
{
GUIUtility.factory.SetLabelWidth(49f);

nameField = content.AddElement(GUIUtility.factory.CreateTextField("Name", newValue => config.name = newValue));
professionField = content.AddElement(GUIUtility.factory.CreateEnumField<ProfessionType>("Class", newValue => config.professionType = newValue));

hpField = content.AddElement(GUIUtility.factory.CreateIntField("HP", newValue => config.hp = newValue));
mpField = content.AddElement(GUIUtility.factory.CreateIntField("MP", newValue => config.mp = newValue));
botToggle = content.AddElement(GUIUtility.factory.CreateToggle("Bot", newValue => config.bot = newValue));

attackField = content.AddElement(GUIUtility.factory.CreateFloatField("Attack", newValue => config.attack = newValue));
defenseField = content.AddElement(GUIUtility.factory.CreateFloatField("Defense", newValue => config.defense = newValue));
criticalSlider = content.AddElement(GUIUtility.factory.CreateSlider("Critical", newValue => config.critical = newValue));

GUIUtility.factory.ResetLabelWidth();

Panel skillPanel = content.AddElement(GUIUtility.factory.CreatePanel("Skill"));
skillListView = skillPanel.AddElement(GUIUtility.factory.CreateListView<string>((item, index) => GUIUtility.factory.CreateTextField("Skill name", newValue => config.skillNameList[index] = newValue)));
skillPanel.AddElement(GUIUtility.factory.CreateAddButton("New Skill", () => skillListView.AddItem(string.Empty)));
}
}

在上述代码中,我们通过directory属性指定 "Assets/Configs/CharacterConfig" 作为配置文件的保存目录。

OnCreateGUI方法中,我们借助 winS.UnityEditor.GUI 扩展包的API来绘制对应的编辑器GUI。

同时,我们定义了一个静态方法Open并为其指定UnityEditor.MenuItem特性。 这使得我们可以通过菜单项 "Example/Window/Character Config Editor" 来打开编辑器。