From aaca1387746d2f52357a9a1c2583700c2ac85c03 Mon Sep 17 00:00:00 2001 From: Joywayer Date: Thu, 30 Jul 2026 08:46:41 +0800 Subject: [PATCH] =?UTF-8?q?fix(editor):=20EnemyAiBrain=20=E6=A3=80?= =?UTF-8?q?=E8=A7=86=E5=99=A8=E6=94=AF=E6=8C=81=E5=A4=9A=E9=80=89=E2=80=94?= =?UTF-8?q?=E2=80=94mixed=20=E5=80=BC=E4=B8=8D=E5=86=8D=E8=AF=AF=E5=86=99?= =?UTF-8?q?=EF=BC=8C=E8=BF=9D=E8=A7=84=E5=AF=B9=E8=B1=A1=E9=80=90=E4=B8=AA?= =?UTF-8?q?=E7=82=B9=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Scripts/Editor/AI/EnemyAiBrainEditor.cs | 49 +++++++++++++------ 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/Assets/_Game/Scripts/Editor/AI/EnemyAiBrainEditor.cs b/Assets/_Game/Scripts/Editor/AI/EnemyAiBrainEditor.cs index c102018d..d9b763de 100644 --- a/Assets/_Game/Scripts/Editor/AI/EnemyAiBrainEditor.cs +++ b/Assets/_Game/Scripts/Editor/AI/EnemyAiBrainEditor.cs @@ -36,8 +36,8 @@ namespace BaseGames.Editor.AI DrawInvariantHelp(); - // 其余字段(若将来新增)照常绘制 - DrawPropertiesExcluding(serializedObject, "m_Script", "_recipe", "_definitionId"); + // 其余字段(若将来新增)照常绘制;m_Script 与项目其他自定义检视器惯例一致,不排除 + DrawPropertiesExcluding(serializedObject, "_recipe", "_definitionId"); serializedObject.ApplyModifiedProperties(); } @@ -50,19 +50,26 @@ namespace BaseGames.Editor.AI string current = _definitionId.stringValue; int index = string.IsNullOrEmpty(current) ? 0 : ids.IndexOf(current); - // 已配的 id 在注册表里找不到(脚本被删/改名)——保留原值并显式标出,不静默清空 - bool missing = index < 0; + bool mixedRecipe = _recipe.hasMultipleDifferentValues; + bool mixedId = _definitionId.hasMultipleDifferentValues; + + // 已配的 id 在注册表里找不到(脚本被删/改名)——保留原值并显式标出,不静默清空。 + // mixed 时 current 只是其中一个对象的值,拿它去查注册表会误报,跳过该判定。 + bool missing = !mixedId && index < 0; if (missing) { ids.Add($"{current} ⚠ 注册表中不存在"); index = ids.Count - 1; } - using (new EditorGUI.DisabledScope(_recipe.objectReferenceValue != null)) + // 选中对象里只要有任何一个已配方,就不该从这里批量写 id + using (new EditorGUI.DisabledScope(_recipe.objectReferenceValue != null || mixedRecipe)) { + EditorGUI.showMixedValue = mixedId; int picked = EditorGUILayout.Popup( new GUIContent("定制脚本 id", "[AiDefinition(id)] 的 AiScript 子类 id。与配方资产二选一"), index, ids.Select(s => new GUIContent(s)).ToArray()); + EditorGUI.showMixedValue = false; if (picked != index) _definitionId.stringValue = picked == 0 ? string.Empty : ids[picked]; @@ -76,21 +83,31 @@ namespace BaseGames.Editor.AI void DrawInvariantHelp() { - if (_recipe.hasMultipleDifferentValues || _definitionId.hasMultipleDifferentValues) - return; // 多选且不一致时不下断言 + // hasMultipleDifferentValues 时 SerializedProperty.objectReferenceValue / + // stringValue 只返回其中一个对象的值,不能整体判断——逐对象检查,把违规的点名。 + var bothSet = new List(); + var neither = new List(); - bool hasRecipe = _recipe.objectReferenceValue != null; - bool hasId = !string.IsNullOrEmpty(_definitionId.stringValue); + foreach (var obj in serializedObject.targetObjects) + { + if (obj == null) continue; + var so = new SerializedObject(obj); + bool hasRecipe = so.FindProperty("_recipe").objectReferenceValue != null; + bool hasId = !string.IsNullOrEmpty(so.FindProperty("_definitionId").stringValue); + if (hasRecipe && hasId) bothSet.Add(obj.name); + else if (!hasRecipe && !hasId) neither.Add(obj.name); + } - if (hasRecipe && hasId) + if (bothSet.Count > 0) EditorGUILayout.HelpBox( - "配方资产与定制脚本 id 同时配置了。二者互斥,运行时 Awake 会报错并禁用本组件。" + - "请清掉其中一项。", MessageType.Error); - else if (!hasRecipe && !hasId) + $"以下对象同时配置了配方资产与定制脚本 id:{string.Join("、", bothSet)}。" + + "二者互斥,运行时 Awake 会报错并禁用组件。请清掉其中一项。", MessageType.Error); + + if (neither.Count > 0) EditorGUILayout.HelpBox( - "尚未配置 AI 来源。约 95% 的敌人应指定配方资产(用菜单 " + - "BaseGames/AI/Enemy AI Recipe Wizard 创建);有独门机制的敌人才写 " + - "[AiDefinition] 的 AiScript 子类并在此选它的 id。", MessageType.Error); + $"以下对象尚未配置 AI 来源:{string.Join("、", neither)}。" + + "约 95% 的敌人应指定配方资产(用菜单 BaseGames/AI/Enemy AI Recipe Wizard 创建);" + + "有独门机制的敌人才写 [AiDefinition] 的 AiScript 子类并在此选它的 id。", MessageType.Error); } } }