一、EditorGUI.BeginChangeCheck()和EditorGUI.EndChangeCheck()

EditorGUI.BeginChangeCheck();

// 相邻对数(普通方块)
int pairCount = currentLevel.adjacentPairCount;
pairCount = EditorGUILayout.IntField("相邻普通方块对数", pairCount);
       
if (EditorGUI.EndChangeCheck())
{
     Undo.RecordObject(currentLevel, "Edit Level Goal Params");
     currentLevel.adjacentPairCount = pairCount;
     EditorUtility.SetDirty(currentLevel);
}
  • EditorGUI.BeginChangeCheck():这个方法标记开始一个变化检查的区域。它的作用是开始追踪在此之后的控件值的变化。在你对某些编辑器控件(比如 EditorGUILayout.IntSlider 或 EditorGUILayout.IntField)进行修改时,这个方法会检查控件的值是否发生了变化。

  • EditorGUI.EndChangeCheck():这个方法标记结束一个变化检查的区域,并返回一个 bool 值,指示在 BeginChangeCheck() 和 EndChangeCheck() 之间的控件值是否发生了变化。如果控件的值有变化,返回 true,否则返回 false。

例子中就是currentLevel.adjacentPairCount的值发生了变化,在检测到变化后,将变化写回到adjacentPairCount。

二、Undo.RecordObject

直观上看Undo是撤销,Record是记录。

Undo.RecordObject的作用就是记录对象的修改,用户可以按下Ctrl+Z撤销这一次修改。

EditorGUI.BeginChangeCheck();

// 相邻对数(普通方块)
int pairCount = currentLevel.adjacentPairCount;
pairCount = EditorGUILayout.IntField("相邻普通方块对数", pairCount);
       
if (EditorGUI.EndChangeCheck())
{
     Undo.RecordObject(currentLevel, "Edit Level Goal Params");
     currentLevel.adjacentPairCount = pairCount;
     EditorUtility.SetDirty(currentLevel);
}

这个例子中,在编辑器修改adjacentPairCount的值之后,就可以按Ctrl+Z撤销。

三、EditorUtility.SetDirty

告诉编辑器你修改了这个数据,unity编辑器并不会自动的保存你修改的数据,你需要告诉编辑器你修改了他。

四、EditorGUILayout.ObjectField

EditorGUILayout.ObjectField 是 Unity 编辑器中用于创建对象选择框(Object Field)的方法,允许用户在编辑器中选择并指定一个对象(如 GameObject、Texture、ScriptableObject 等)作为输入。它可以在自定义的编辑器窗口或自定义 Inspector 中显示一个可供选择的对象字段,用户可以通过它来选择或拖放对象。

比如展示一个Sprite的选择框:

currentLevel.featureIcon = (Sprite)EditorGUILayout.ObjectField(
                "关卡特点 Icon",
                currentLevel.featureIcon,
                typeof(Sprite),
                false);

五、EditorGUILayout.HelpBox

基本语法:

EditorGUILayout.HelpBox(string message, MessageType type);

// 显示信息类型的 HelpBox
EditorGUILayout.HelpBox("这是一个普通的信息框。", MessageType.Info);
// 显示警告类型的 HelpBox
EditorGUILayout.HelpBox("这是一个警告信息,请注意!", MessageType.Warning);
// 显示错误类型的 HelpBox
EditorGUILayout.HelpBox("这是一个错误信息,操作无效!", MessageType.Error);
EditorGUILayout.HelpBox("存在特殊方块类型为空的配置行,请检查。", MessageType.Warning);

六、GUILayout.Label

展示一个静态文本在编辑器中,也可以展示图像。

// 1. 简单文字
GUILayout.Label("这是一个简单的标签");

// 2.带样式
GUIStyle style = new GUIStyle();
style.fontSize = 16;
style.normal.textColor = Color.red;
GUILayout.Label("这是一个带样式的标签", style);

// 3.指定高度、宽度
GUILayout.Label("这是一个指定了宽度和高度的标签", GUILayout.Width(300), GUILayout.Height(40));

// 4. 展示个图片
Texture  myTexture = AssetDatabase.LoadAssetAtPath<Texture>("Assets/01_GameRes/CommonRes/Sprites/btn_icon_rocket.png");
if (myTexture != null)
{
    // 显示图片,设置宽度和高度
    GUILayout.Label(myTexture, GUILayout.Width(20), GUILayout.Height(20));
}

七、GUILayout.Toggle

                bool active = cell.active;
                string label = active ? "■" : "□";

                bool newActive = GUILayout.Toggle(
                    active,
                    label,
                    "Button",
                    GUILayout.Width(CellSize),
                    GUILayout.Height(CellSize));

参数:

value (bool):表示当前切换按钮的状态。如果 value 为 true,按钮会处于选中状态,反之则为未选中状态。

label (string):按钮旁边的标签,可以是任何文本,通常用于给用户提供一些说明。

style (string):按钮的样式,通常是一个字符串,表示该按钮的 GUI 风格,默认为 "Button"。你也可以使用 GUIStyle 进行自定义样式。

GUILayoutOption[] options:可以设置控件的宽度、最小/最大尺寸等布局选项,例如 GUILayout.Width() 和 GUILayout.Height()。

八. 根据类型找到Assets下的资源

SO_LevelConfig 是我的一个ScriptObject

private SO_LevelConfig FindLevelById(int id)
    {
        string[] guids = AssetDatabase.FindAssets("t:SO_LevelConfig", new[] { levelFolder });
        foreach (var guid in guids)
        {
            string path = AssetDatabase.GUIDToAssetPath(guid);
            var level = AssetDatabase.LoadAssetAtPath<SO_LevelConfig>(path);
            if (level != null && level.levelId == id)
                return level;
        }
        return null;
    }

levelFolder 以及其所有子文件夹 中,找到所有 SO_LevelConfig 资源,逐个加载,返回第一个 levelId == id 的关卡;如果找不到就返回 null

九. 编辑器中的文件夹操作

判断文件夹是否存在:

AssetDatabase.IsValidFolder(levelFoler)

创建文件夹:

AssetDatabase.CreateFolder(parent, folderName);
AssetDatabase.Refresh();    //注意刷新

十、Unity提示框

// 未找到,提示创建
bool create = EditorUtility.DisplayDialog(
                "未找到关卡",
                $"目录 {levelFolder} 中没有 ID 为 {targetLevelId} 的关卡,是否创建?",
                "创建",
                "取消");

if (create)
{
    CreateLevel(targetLevelId);
}

EditorUtility.DisplayDialog参数分别为[title],[message],[ok],[cancel]。

EditorUtility.DisplayDialog点“创建”返回true,关闭返回false。

四、保存一个Scriptobject资源,并刷新项目

    [BoxGroup("操作"), Button("保存当前关卡")]
    private void SaveCurrentLevel()
    {
        if (currentLevel == null)
        {
            EditorUtility.DisplayDialog("提示", "当前没有关卡被加载", "OK");
            return;
        }

        EditorUtility.SetDirty(currentLevel);
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();

        EditorUtility.DisplayDialog("保存成功", $"已保存关卡 ID: {currentLevel.levelId}", "OK");
    }

重点是下面三句。

EditorUtility.SetDirty(currentLevel);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();

十一、GUIContent

public GUIContent(string text, Texture image, string tooltip)

看上去就是对一个text、image和提示的封装,看到Button的构造有GUIContent就看一下。

Logo

这里是一个专注于游戏开发的社区,我们致力于为广大游戏爱好者提供一个良好的学习和交流平台。我们的专区包含了各大流行引擎的技术博文,涵盖了从入门到进阶的各个阶段,无论你是初学者还是资深开发者,都能在这里找到适合自己的内容。除此之外,我们还会不定期举办游戏开发相关的活动,让大家更好地交流互动。加入我们,一起探索游戏开发的奥秘吧!

更多推荐