
1. CanEditMultipleObjects 属性添加到类上面在自定义编辑器时允许多对象编辑即同时选中多个物体统一修改共同的值。知识补充默认情况下Unity 的 Inspector 面板在同时选中多个物体时只会显示第一个物体的属性。添加该属性后编辑器会进入多对象编辑模式允许你统一修改多个物体共有的属性值。配合 SerializedProperty 的 hasMultipleDifferentValues 属性还可以判断多个物体在该字段上是否存在差异从而在自定义编辑器中实现更精细的控制。2. CustomEditor 属性添加到类上面为一个组件或者脚本自定义属性面板定义类要继承 Editor 类using System.Collections; using System.Collections.Generic; using UnityEngine; public class EditorAttribute : MonoBehaviour { // 属性必须是 public 的并且和你自定义编辑器中的类型是一致的比如这里是 int // 类型你在编辑器中就用 IntSlider public int damage; public int armor; public GameObject gun; }using UnityEngine; using UnityEditor; [CustomEditor(typeof(EditorAttribute))] public class EditorAttributes : Editor { SerializedProperty damageProp; SerializedProperty armorProp; SerializedProperty gunProp; void OnEnable() { // Setup the SerializedProperties. damageProp serializedObject.FindProperty(damage); armorProp serializedObject.FindProperty(armor); gunProp serializedObject.FindProperty(gun); } public override void OnInspectorGUI() { // Update the serializedProperty - always do this in the beginning of OnInspectorGUI. serializedObject.Update(); // Show the custom GUI controls. EditorGUILayout.IntSlider(damageProp, 0, 100, new GUIContent(Damage)); // Only show the damage progress bar if all the objects have the same damage value: if (!damageProp.hasMultipleDifferentValues) ProgressBar(damageProp.intValue / 100.0f, Damage); EditorGUILayout.IntSlider(armorProp, 0, 100, new GUIContent(Armor)); // Only show the armor progress bar if all the objects have the same armor value: if (!armorProp.hasMultipleDifferentValues) ProgressBar(armorProp.intValue / 100.0f, Armor); EditorGUILayout.PropertyField(gunProp, new GUIContent(Gun Object)); // Apply changes to the serializedProperty - always do this in the end of OnInspectorGUI. serializedObject.ApplyModifiedProperties(); } // Custom GUILayout progress bar. void ProgressBar(float value, string label) { // Get a rect for the progress bar using the same margins as a textfield: Rect rect GUILayoutUtility.GetRect(18, 18, TextField); EditorGUI.ProgressBar(rect, value, label); EditorGUILayout.Space(); } }知识补充CustomEditor 是 Unity 编辑器扩展中最常用的属性之一。通过它你可以完全接管某个组件在 Inspector 面板中的显示方式实现自定义的 GUI 布局、进度条、滑块等控件。配合 SerializedObject 和 SerializedProperty可以安全地读写序列化字段并自动处理多选、撤销等操作。需要注意的是自定义编辑器类必须放在 Editor 文件夹下且类名通常以 Editor 结尾以保持命名规范。3. InitializeOnLoad 属性添加在类上。当重新编译项目中的脚本时将调用具有此属性的静态构造函数。这发生在 Unity 第一次加载你的项目的时候也发生在 Unity 检测到脚本的修改的时候就是执行该类的静态构造函数知识补充InitializeOnLoad 属性通常用于在编辑器启动或脚本重编译后执行一次性的初始化逻辑例如注册自定义快捷键、初始化静态数据、监听编辑器事件等。它要求目标类必须有一个静态构造函数且该类通常放在 Editor 文件夹下。需要注意的是静态构造函数在编辑器生命周期内可能被多次调用每次脚本重编译都会触发因此初始化逻辑应当具备幂等性避免重复注册或重复创建资源。4. InitializeOnLoadMethod 属性InitializeOnLoadMethod 与 InitializeOnLoad 功能类似但它是直接标记在静态方法上无需定义静态构造函数写法更简洁。该方法会在 Unity 编辑器加载完成或脚本重新编译后自动调用一次非常适合用于注册编辑器菜单、初始化调试工具、订阅编辑器事件等场景。需要注意的是该方法必须是静态的且所在类应放在 Editor 文件夹下。using UnityEngine; using UnityEditor; class MyClass { [InitializeOnLoadMethod] static void OnProjectLoadedInEditor() { Debug.Log(Project loaded in Unity Editor); } }5. MenuItem知识补充MenuItem 是 Unity 编辑器扩展中最常用的属性之一常用于在菜单栏、组件右键菜单或 GameObject 菜单中添加自定义功能。第二个参数为 true 时该方法作为验证函数用于控制菜单项是否可点击例如未选中物体时置灰为 false 时则是实际执行函数。第三个参数 priority 不仅控制菜单项的排列顺序还影响分组显示相邻项优先级差值大于等于 11 时会被自动分组中间以分割线隔开。此外通过 CONTEXT/组件名/菜单名 的路径写法可以为指定组件添加右键菜单配合 MenuCommand 参数可以获取被右键点击的组件实例。添加到 static 方法上面MenuItem 添加一个菜单项。该菜单项可以有快捷键路径与快捷键之间要有空格隔开%ctrl on Windows, cmd on macOS、#shift、alt。如果不需要这三个键组合直接下划线后面加个键名就可以了。比如 shiftaltg 使用MyMenu/Do Something #g或者g使用MyMenu/Do Something _g。一些特殊的键盘键被支持为热键例如#LEFT表示 shiftleft 箭头。支持的键包括LEFT、RIGHT、UP、DOWN、F1 .. F12、HOME、END、PGUP、PGDN。小键盘上的键都是大写的。当添加菜单项到 GameObject/ 菜单创建自定义游戏对象时一定要调用 GameObjectUtility.SetParentAndAlign 确保新的游戏物体的层级和位置关系正确或者使用 Undo.RegisterCreatedObjectUndo 撤销操作使用 Selection.activeObject 选中创建的物体。并且创建的菜单可以根据优先级分层级。MenuItem 有三个参数第一个是菜单栏的路径第二个表示如果有相同名字的菜单栏优先执行哪一个方法为 true 则执行该方法为 false 则表示不执行该方法第三个参数为优先级表示上下排列的顺序小的在上不写则默认为 1000。另外如果相邻的两个 priority 参数值相差 11则认为是不同组的中间会有线分割显示using UnityEditor; using UnityEngine; public class MenuTest : MonoBehaviour { [MenuItem(MyMenu/Do Something)] static void DoSomething() { Debug.Log(Doing Something...); } [MenuItem(MyMenu/Log Selected Transform Name)] static void LogSelectedTransformName() { Debug.Log(Selected Transform is on Selection.activeTransform.gameObject.name .); } [MenuItem(MyMenu/Log Selected Transform Name, true)] static bool ValidateLogSelectedTransformName() { // Return false if no transform is selected. return Selection.activeTransform ! null; } [MenuItem(MyMenu/Log Selected Transform Name, false)] static void Show() { // Return false if no transform is selected. Debug.Log(Selection.activeTransform ! null); } // Add a menu item named Do Something with a Shortcut Key to MyMenu in the menu bar // and give it a shortcut (ctrl-g on Windows, cmd-g on macOS). [MenuItem(MyMenu/Do Something with a Shortcut Key %g)] static void DoSomethingWithAShortcutKey() { Debug.Log(Doing something with a Shortcut Key...); } // Add a menu item called Double Mass to a Rigidbodys context menu. // 给指定组件右键添加一个属性contextMenu只是给脚本组件右键添加一个属性 // MenuCommand 有两个属性context 表示右键点击的组件 // CONTEXT/Rigidbody/Double MassCONTEXT 固定写法Rigidbody 目标添加属性的组件名字可以是自定义脚本这样就和 contextMenu 一样了 [MenuItem(CONTEXT/Rigidbody/Double Mass)] static void DoubleMass(MenuCommand command) { Rigidbody body (Rigidbody)command.context; body.mass body.mass * 2; Debug.Log(Doubled Rigidbodys Mass to body.mass from Context Menu.); } // Add a menu item to create custom GameObjects. // Priority 1 ensures it is grouped with the other menu items of the same kind // and propagated to the hierarchy dropdown and hierarchy context menus. [MenuItem(GameObject/MyCategory/Custom Game Object, false, 10)] static void CreateCustomGameObject(MenuCommand menuCommand) { // Create a custom game object GameObject go new GameObject(Custom Game Object); // Ensure it gets reparented if this was a context click (otherwise does nothing) GameObjectUtility.SetParentAndAlign(go, menuCommand.context as GameObject); // Register the creation in the undo system Undo.RegisterCreatedObjectUndo(go, Create go.name); Selection.activeObject go; } }6. ContextMenu 属性添加到方法上面为指定组件在 Inspector 面板中右键添加一个菜单项。与 MenuItem 的 CONTEXT/组件名/菜单名 写法效果类似但 ContextMenu 直接写在组件脚本内部使用更简洁。using UnityEngine; public class MyComponent : MonoBehaviour { [ContextMenu(Reset Position)] void ResetPosition() { transform.position Vector3.zero; Debug.Log(Position reset.); } [ContextMenu(Log Info)] void LogInfo() { Debug.Log(Name: gameObject.name); } }知识补充ContextMenu 属性非常适合在开发调试阶段快速添加右键操作例如重置数据、打印日志、执行测试逻辑等。它不需要额外编写 Editor 类直接在 MonoBehaviour 脚本中标记即可。配合 ContextMenuItem 属性还可以为字段添加右键菜单方便在 Inspector 中直接对字段执行操作。7. ContextMenuItem 属性添加到字段上面为 Inspector 面板中的某个字段添加右键菜单项。当你在字段上右键时会看到自定义的菜单选项点击后执行对应的方法。using UnityEngine; public class MyComponent : MonoBehaviour { [ContextMenuItem(Randomize, RandomizeValue)] public int value 10; void RandomizeValue() { value Random.Range(0, 100); Debug.Log(Value randomized to value); } }知识补充ContextMenuItem 接收两个参数第一个是菜单显示名称第二个是要执行的方法名。该方法必须是当前类中的实例方法且不能带参数。这个属性非常适合在调试时快速修改字段值例如随机化数值、重置默认值、复制粘贴配置等。8. Header 属性添加到字段上面Header 属性会在字段上方绘制一个带背景色的标题栏视觉上把相关字段归为一组。它本身不改变字段的存储方式只影响 Inspector 面板的显示效果。通常与 Space 属性配合使用在分组之间增加间距让面板结构更清晰。using UnityEngine; public class PlayerConfig : MonoBehaviour { [Header(基础属性)] public string playerName; public int level; [Header(战斗属性)] public int attack; public int defense; public int health; }9. Space 属性添加到字段上面在 Inspector 面板中为字段上方添加一段空白间距用于在视觉上分隔不同分组的字段。using UnityEngine; public class PlayerConfig : MonoBehaviour { [Header(基础属性)] public string playerName; public int level; [Space(20)] [Header(战斗属性)] public int attack; public int defense; public int health; }知识补充Space 属性可以接收一个整数参数表示间距的像素大小不写则使用默认间距。它常用于在字段分组之间制造视觉分隔让 Inspector 面板更易读。与 Header 属性搭配使用可以快速构建出结构清晰的属性面板。10. Tooltip 属性添加到字段上面当鼠标悬停在 Inspector 面板中的字段名称上时显示一段提示文字帮助使用者理解该字段的含义。using UnityEngine; public class PlayerConfig : MonoBehaviour { [Tooltip(角色的最大生命值)] public int maxHealth 100; [Tooltip(角色的移动速度单位米/秒)] public float moveSpeed 5f; }11. Range 属性添加到数值字段上面在 Inspector 面板中将字段显示为滑动条并限制数值的取值范围。using UnityEngine; public class PlayerConfig : MonoBehaviour { [Range(0, 100)] public int health 50; [Range(0f, 1f)] public float volume 0.8f; }12. SerializeField 属性添加到字段上面强制 Unity 序列化该字段使其在 Inspector 面板中可见并可编辑即使该字段是 private 的。using UnityEngine; public class PlayerConfig : MonoBehaviour { [SerializeField] private int health 100; [SerializeField] private string playerName Player; }13. HideInInspector 属性添加到字段上面在 Inspector 面板中隐藏该字段但字段仍然会被 Unity 序列化保存。using UnityEngine; public class PlayerConfig : MonoBehaviour { [HideInInspector] public int internalId 0; public string playerName Player; }14. RequireComponent 属性添加到类上面自动为挂载该脚本的 GameObject 添加所依赖的组件并在移除依赖组件时给出警告。using UnityEngine; [RequireComponent(typeof(Rigidbody))] [RequireComponent(typeof(BoxCollider))] public class PlayerController : MonoBehaviour { void Start() { // 直接使用依赖组件无需手动检查 Rigidbody rb GetComponentRigidbody(); rb.AddForce(Vector3.up * 10f); } }知识补充RequireComponent 可以接收多个组件类型Unity 会自动为挂载该脚本的 GameObject 添加缺失的依赖组件并在运行时保证这些组件一定存在。这可以避免在代码中频繁使用 GetComponent 判空提升代码的健壮性。需要注意的是如果手动删除依赖组件Unity 会弹出警告提示防止误操作。15. DisallowMultipleComponent 属性添加到类上面禁止同一个 GameObject 上重复挂载多个该组件实例。using UnityEngine; [DisallowMultipleComponent] public class SingleComponent : MonoBehaviour { public int value 1; }知识补充DisallowMultipleComponent 用于限制同一 GameObject 上只能存在一个该组件实例。当尝试重复添加时Unity 会阻止操作并给出提示。这个属性非常适合那些逻辑上只应存在一份的组件例如玩家控制器、游戏管理器、单例类等可以有效避免因重复挂载导致的逻辑冲突。16. AddComponentMenu 属性添加到类上面在 Unity 编辑器的 Component 菜单中为脚本指定一个自定义的添加路径方便快速查找和添加组件。using UnityEngine; [AddComponentMenu(Custom/Player/PlayerController)] public class PlayerController : MonoBehaviour { public float speed 5f; }知识补充AddComponentMenu 可以自定义脚本在 Component 菜单中的显示路径将相关组件归类到自定义目录下避免脚本过多时菜单混乱。路径使用斜杠分隔层级例如 Custom/Player/PlayerController 会在 Component 菜单中创建 Custom 下的 Player 子菜单。这个属性非常适合项目中有大量自定义组件时使用能够显著提升开发效率。17. ExecuteInEditMode 属性添加到类上面使脚本在编辑器未运行状态下也能执行 Update、OnGUI 等生命周期方法常用于编辑器内的实时预览和调试。using UnityEngine; [ExecuteInEditMode] public class GizmoPreview : MonoBehaviour { void Update() { // 在编辑器未运行时也会执行 Debug.Log(Update called in Edit Mode); } }知识补充ExecuteInEditMode 让 MonoBehaviour 脚本在编辑器模式下也能运行生命周期方法非常适合用于场景预览、辅助线绘制、数据同步等场景。但需要注意编辑器模式下 Update 的调用频率与运行时不同且场景保存、加载、脚本重编译等操作都可能触发方法调用因此逻辑需要具备幂等性避免产生副作用或性能问题。18. Gizmos 相关属性OnDrawGizmos / OnDrawGizmosSelected添加到方法上面在 Scene 视图中绘制辅助图形用于可视化调试信息。OnDrawGizmos 始终绘制OnDrawGizmosSelected 仅在物体被选中时绘制。using UnityEngine; public class GizmoPreview : MonoBehaviour { void OnDrawGizmos() { // 始终绘制 Gizmos.color Color.yellow; Gizmos.DrawWireSphere(transform.position, 1f); } void OnDrawGizmosSelected() { // 仅选中时绘制 Gizmos.color Color.red; Gizmos.DrawWireCube(transform.position, Vector3.one * 2f); } }知识补充Gizmos 辅助图形是 Unity 场景调试的重要工具。OnDrawGizmos 在 Scene 视图中始终绘制辅助图形适合展示常驻的可视化信息OnDrawGizmosSelected 仅在物体被选中时绘制适合展示选中态的详细信息。配合 Gizmos.color、Gizmos.DrawWireSphere、Gizmos.DrawLine 等方法可以直观地展示碰撞范围、路径点、寻路网格等调试信息大幅提升开发调试效率。