Unity中如何同时启用自定义编辑器工具与地形Paint texture工具?
问题描述
我做了一个简单的自定义编辑器工具,能让鼠标位置保持水平直线,用来在地形上绘制直线纹理。但开启Inspector里地形编辑器的「Paint Texture」工具时,自定义工具就会被禁用;反过来选中自定义工具时,「Paint Texture」工具也会失效。请问怎么才能让这两个工具同时启用?
现象截图
- 自定义工具选中但Paint Texture已停用:

- 选中Paint Texture时自定义工具被取消选中:

自定义工具的OnToolGUI方法代码
public override void OnToolGUI(EditorWindow window) { HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive)); Event e = Event.current; if (!(window is SceneView)) return; if (!ToolManager.IsActiveTool(this)) return; if (e.shift) { if (e.type == EventType.MouseDown) { if (e.button == 0) { downY = e.mousePosition.y; } } if (e.type == EventType.MouseDrag) { if (e.button == 0) { e.mousePosition = new Vector2(e.mousePosition.x, downY); Debug.Log("Mouse Position: " + e.mousePosition); } } } }
解决方法
Unity默认工具系统是互斥的,选中一个就会取消另一个。要实现两者同时生效,得换个思路——要么把自定义逻辑做成全局辅助工具,要么修改自定义工具的判断逻辑,兼容地形工具的激活状态。
方案1:监听SceneView全局事件(推荐)
放弃继承EditorTool,改用SceneView.duringSceneGui全局事件注入鼠标逻辑,这样不管当前激活的是哪个地形工具,只要在SceneView里就能生效。修改后的代码示例:
[InitializeOnLoad] public class StraightLinePainterHelper { private static float downY; static StraightLinePainterHelper() { SceneView.duringSceneGui += OnSceneGUI; } private static void OnSceneGUI(SceneView sceneView) { // 只在地形Paint Texture工具激活且按住Shift时生效,可按需调整判断条件 if (!Terrain.activeTerrain || !IsTerrainPaintToolActive()) return; Event e = Event.current; if (e.shift) { if (e.type == EventType.MouseDown && e.button == 0) { downY = e.mousePosition.y; } if (e.type == EventType.MouseDrag && e.button == 0) { e.mousePosition = new Vector2(e.mousePosition.x, downY); e.Use(); // 关键:标记事件已处理,让地形工具使用修改后的鼠标位置 } } } // 判断当前是否激活了地形的Paint Texture工具 private static bool IsTerrainPaintToolActive() { TerrainEditor terrainEditor = TerrainEditor.activeTerrainEditor; if (terrainEditor == null) return false; return terrainEditor.selectedTool is TerrainToolPaintTexture; } }
方案2:修改自定义工具的激活判断逻辑
如果一定要保留EditorTool的形式,需要去掉自定义工具的激活判断,转而监听地形工具的状态,同时避免抢占地形工具的输入焦点:
public override void OnToolGUI(EditorWindow window) { // 移除默认控件设置,避免抢占地形工具的输入焦点 // HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive)); Event e = Event.current; if (!(window is SceneView)) return; // 判断地形Paint Texture工具是否激活,而非自定义工具本身 TerrainEditor terrainEditor = TerrainEditor.activeTerrainEditor; if (terrainEditor == null || !(terrainEditor.selectedTool is TerrainToolPaintTexture)) return; if (e.shift) { if (e.type == EventType.MouseDown && e.button == 0) { downY = e.mousePosition.y; } if (e.type == EventType.MouseDrag && e.button == 0) { e.mousePosition = new Vector2(e.mousePosition.x, downY); e.Use(); // 确保地形工具接收修改后的鼠标位置 } } }
关键注意点
e.Use()是核心:它会告诉Unity这个事件已被处理,确保修改后的鼠标位置能被地形工具正确接收,同时避免事件冲突。- 方案1的体验更流畅:不需要手动切换工具,只要打开地形Paint工具并按住Shift,就自动启用直线绘制逻辑。
内容的提问来源于stack exchange,提问作者Tushar
相关产品推荐
相关产品推荐

