一、EditorGUI.BeginChangeCheck()和EditorGUI.EndChangeCheck()
cs
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撤销这一次修改。
cs
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的选择框:
cs
currentLevel.featureIcon = (Sprite)EditorGUILayout.ObjectField(
"关卡特点 Icon",
currentLevel.featureIcon,
typeof(Sprite),
false);

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

六、GUILayout.Label
展示一个静态文本在编辑器中,也可以展示图像。
cs
// 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
cs
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
cs
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。
九. 编辑器中的文件夹操作
判断文件夹是否存在:
cs
AssetDatabase.IsValidFolder(levelFoler)
创建文件夹:
cs
AssetDatabase.CreateFolder(parent, folderName);
AssetDatabase.Refresh(); //注意刷新
十、Unity提示框
cs
// 未找到,提示创建
bool create = EditorUtility.DisplayDialog(
"未找到关卡",
$"目录 {levelFolder} 中没有 ID 为 {targetLevelId} 的关卡,是否创建?",
"创建",
"取消");
if (create)
{
CreateLevel(targetLevelId);
}
EditorUtility.DisplayDialog参数分别为[title],[message],[ok],[cancel]。
EditorUtility.DisplayDialog点"创建"返回true,关闭返回false。
四、保存一个Scriptobject资源,并刷新项目
cs
[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就看一下。