在实际的 Unity 项目里,有很多对象是运行时自动生成的、由系统维护的或者依赖复杂逻辑的。如果能随便改它们,很容易导致数据错乱、功能失效,甚至场景崩掉。所以,Unity 提供了 HideFlags 这套机制来"保护现场"。
保护对象
cs
HideFlags.NotEditable // 不能编辑
HideFlags.HideInHierarchy // 在层级里隐藏
HideFlags.DontSave // 不保存到场景
HideFlags.HideAndDontSave // 完全隐身+不保存
组合起来可以实现:
-
"你看不见"
-
"你看得见但不能动"
-
"运行完就消失"
示例代码
cs
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;
[ExecuteInEditMode]
public class LockTest : MonoBehaviour
{
void Update()
{
if (GameObject.Find("LockedObject") == null)
{
GameObject obj = new GameObject("LockedObject");
obj.hideFlags = HideFlags.None;
// obj.hideFlags = HideFlags.NotEditable;
}
}
}
说明:在编辑器状态(没点 Play)也会执行,每一帧都在检查,如果没有这个物体 → 就创建一个。 编辑器守护进程:
-
你删掉对象 → 下一帧给你补回来
-
你改名字 → 逻辑可能失效再生成
-
你清空场景 → 它又生成
HideFlags 到底是什么
它本质是一个位标记(bitmask),可以理解为给 GameObject 打标签,告诉 Unity:"这个东西该怎么对待"。
通用工具
cs
using UnityEditor;
using UnityEngine;
public class EditableControlMenu
{
// =========================
// 锁定选中对象(包含子物体)
// =========================
[MenuItem("Tools/Lock Selected %#l")] // Ctrl+Shift+L
static void LockSelected()
{
var selection = Selection.gameObjects;
if (selection.Length == 0)
{
Debug.LogWarning("No GameObject selected.");
return;
}
int count = 0;
foreach (var obj in selection)
{
// 避免锁 Prefab Root(重要)
if (PrefabUtility.IsAnyPrefabInstanceRoot(obj))
{
Debug.LogWarning($"Skip Prefab Root: {obj.name}");
continue;
}
count += ApplyToHierarchy(obj, true);
}
Debug.Log($"Locked {count} objects.");
}
// =========================
// 解锁选中对象(包含子物体)
// =========================
[MenuItem("Tools/Unlock Selected %#u")] // Ctrl+Shift+U
static void UnlockSelected()
{
var selection = Selection.gameObjects;
if (selection.Length == 0)
{
Debug.LogWarning("No GameObject selected.");
return;
}
int count = 0;
foreach (var obj in selection)
{
count += ApplyToHierarchy(obj, false);
}
Debug.Log($"Unlocked {count} objects.");
}
// =========================
// 一键解锁所有对象(救命按钮)
// =========================
[MenuItem("Tools/Force Unlock ALL")]
static void UnlockAll()
{
var all = Object.FindObjectsOfType<GameObject>(true);
int count = 0;
foreach (var obj in all)
{
if (obj.hideFlags != HideFlags.None)
{
Undo.RecordObject(obj, "Force Unlock");
obj.hideFlags = HideFlags.None;
EditorUtility.SetDirty(obj);
count++;
}
}
Debug.Log($"Force Unlocked {count} objects (ALL).");
}
// =========================
// 核心逻辑:递归处理层级
// =========================
static int ApplyToHierarchy(GameObject root, bool lockState)
{
int count = 0;
var transforms = root.GetComponentsInChildren<Transform>(true);
foreach (var t in transforms)
{
var obj = t.gameObject;
// 已经是目标状态就跳过
if (lockState && obj.hideFlags == HideFlags.NotEditable)
continue;
if (!lockState && obj.hideFlags == HideFlags.None)
continue;
Undo.RecordObject(obj, lockState ? "Lock Object" : "Unlock Object");
obj.hideFlags = lockState ? HideFlags.NotEditable : HideFlags.None;
EditorUtility.SetDirty(obj);
count++;
}
return count;
}
}

快捷键
-
Ctrl + Shift + L → 锁定对象
-
Ctrl + Shift + U → 解锁对象
注意事项
-
仅在 Unity Editor 中有效
-
不影响打包运行
-
不建议锁定 Prefab Root
-
Force Unlock 会影响所有隐藏对象,请谨慎使用
获取链接
Unity3D 编辑器对象锁定工具