diff --git a/Assets/_Game/Scripts/Enemies/Abilities/EnemyAbilityBase.cs b/Assets/_Game/Scripts/Enemies/Abilities/EnemyAbilityBase.cs
index 98b7ec86..42d1a474 100644
--- a/Assets/_Game/Scripts/Enemies/Abilities/EnemyAbilityBase.cs
+++ b/Assets/_Game/Scripts/Enemies/Abilities/EnemyAbilityBase.cs
@@ -182,6 +182,20 @@ namespace BaseGames.Enemies.Abilities
$"实际 = {(_config != null ? _config.GetType().Name : "null")}。请重建为正确的子类 SO。", this);
return null;
}
+
+#if UNITY_EDITOR
+ /// 选中时绘制攻击射程范围(编辑器可视化辅助,不影响运行时)。
+ private void OnDrawGizmosSelected()
+ {
+ if (_config == null || _config.category != AbilityCategory.Attack || _config.rangeRadius <= 0f) return;
+ float sign = transform.localScale.x < 0f ? -1f : 1f;
+ Vector3 origin = transform.position
+ + new Vector3(_config.rangeOffset.x * sign, _config.rangeOffset.y, 0f);
+ UnityEditor.Handles.color = new Color(1f, 0.4f, 0.2f, 0.9f);
+ UnityEditor.Handles.DrawWireDisc(origin, Vector3.forward, _config.rangeRadius);
+ UnityEditor.Handles.Label(origin, $"{_config.abilityId} range");
+ }
+#endif
}
/// WaitForSeconds 池(架构 §10 GC 优化)。能力协程统一通过此获取等待指令。
diff --git a/Assets/_Game/Scripts/Enemies/Abilities/EnemyAbilitySO.cs b/Assets/_Game/Scripts/Enemies/Abilities/EnemyAbilitySO.cs
index 856c200e..a6382088 100644
--- a/Assets/_Game/Scripts/Enemies/Abilities/EnemyAbilitySO.cs
+++ b/Assets/_Game/Scripts/Enemies/Abilities/EnemyAbilitySO.cs
@@ -1,4 +1,6 @@
+using System.Collections.Generic;
using UnityEngine;
+using BaseGames.Core;
namespace BaseGames.Enemies.Abilities
{
@@ -8,7 +10,7 @@ namespace BaseGames.Enemies.Abilities
/// 由对应 EnemyAbilityBase 子类组件读取并执行。
///
[CreateAssetMenu(menuName = "BaseGames/Enemies/Enemy Ability", fileName = "EAB_")]
- public class EnemyAbilitySO : ScriptableObject
+ public class EnemyAbilitySO : ScriptableObject, IValidatable
{
[Header("标识")]
[Tooltip("BD 任务通过此 Id 调用能力(如 \"melee_combo\" / \"blink_strike\")")]
@@ -54,5 +56,13 @@ namespace BaseGames.Enemies.Abilities
[Min(0f)] public float rangeRadius = 0f;
[Tooltip("范围圆心相对敌人的偏移(m),X 随朝向翻转")]
public Vector2 rangeOffset = Vector2.zero;
+
+ /// SOValidationRunner 自动扫描调用:校验 Attack 类招式必须配置有效射程。
+ public IEnumerable Validate()
+ {
+ if (category == AbilityCategory.Attack && rangeRadius <= 0f)
+ yield return ValidationResult.Error(
+ $"能力 \"{abilityId}\" category=Attack 但 rangeRadius<=0,攻击选择器永远选不中该招式,请补齐 rangeRadius。");
+ }
}
}