telegraphVfxKey / telegraphDuration / TelegraphRoutine 删除。 预警的正确载体是 clip 本身——姿态在动画里,音效与特效在动画事件上 (PlaySFX / TriggerFeedback 已于阶段一补接)。旧路径会在动画之前 插一段无动画的静止等待,是同一件事的第二条平行路。 AbilityRunState.Telegraph 枚举值保留:BlinkStrikeAbility 现身闪光段 仍在自己协程里显式置位(计划原文假设它零消费者,实测不成立), 只删了基类的默认预警协程。顺带清掉该文件里遗留的行为树插件措辞。 18 个 ABL_ 资产经 AssetDatabase.ForceReserializeAssets 重写, 去掉已删字段的死键;顺带补齐了这些旧资产缺失的当前字段默认值 (designNote / category / weight / rangeRadius / rangeOffset / maxDashDuration), 无任何已有取值被改动。SOValidationRunner:0 错误 0 警告。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
70 lines
3.2 KiB
C#
70 lines
3.2 KiB
C#
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
using BaseGames.Core;
|
||
|
||
namespace BaseGames.Enemies.Abilities
|
||
{
|
||
/// <summary>
|
||
/// 能力配置包(架构 07_EnemyModule §8.2)。
|
||
/// 一个能力 = 一组攻击段 + 公共参数(冷却/中断规则)。
|
||
/// 预警不在此配置:预警的载体是动画 clip 本身(姿态在动画里,音效与特效挂动画事件)。
|
||
/// 由对应 EnemyAbilityBase 子类组件读取并执行。
|
||
/// </summary>
|
||
[CreateAssetMenu(menuName = "BaseGames/Enemies/Enemy Ability", fileName = "ABL_")]
|
||
public class EnemyAbilitySO : ScriptableObject, IValidatable
|
||
{
|
||
[Header("标识")]
|
||
[Tooltip("能力唯一 id(全小写英文 + 下划线,如 \"melee_combo\" / \"blink_strike\")。" +
|
||
"AI 图与选招器通过它引用本能力")]
|
||
public string abilityId = "ability_id";
|
||
|
||
[TextArea(1, 4)]
|
||
[Tooltip("设计备注(仅供编辑器参考,不影响运行)")]
|
||
public string designNote;
|
||
|
||
[Header("攻击序列")]
|
||
public EnemyAttackSO[] attackSequence;
|
||
|
||
[Header("冷却(秒,从能力执行结束开始计)")]
|
||
[Min(0f)] public float cooldown = 1.5f;
|
||
|
||
[Header("中断规则")]
|
||
[Tooltip("受击时是否打断能力(false=能力具霸体)")]
|
||
public bool interruptOnHurt = true;
|
||
[Tooltip("Stagger 时是否打断(一般为 true)")]
|
||
public bool interruptOnStagger = true;
|
||
|
||
[Header("调度提示(供 AI 选择参考,不强制)")]
|
||
[Min(0f)] public float preferredMinRange = 0f;
|
||
[Min(0f)] public float preferredMaxRange = 5f;
|
||
public bool requiresLineOfSight = true;
|
||
public bool requiresGrounded = true;
|
||
|
||
[Header("互斥组与调度优先级")]
|
||
[Tooltip("互斥组名:同组能力只能有一个同时执行,执行时自动中断同组其他能力;为空 = 无互斥")]
|
||
public string exclusionGroup = "";
|
||
[Tooltip("AI 调度优先级(值越高越优先被选择,冷却就绪时对比)")]
|
||
[Min(0)] public int priority = 0;
|
||
|
||
[Header("选招(攻击选择器用)")]
|
||
[Tooltip("能力调度分类;攻击选择器只从 Attack 类里选招")]
|
||
public AbilityCategory category = AbilityCategory.None;
|
||
[Tooltip("WeightedRandom 模式下的相对权重(越大越易被选)")]
|
||
[Min(0f)] public float weight = 1f;
|
||
|
||
[Header("攻击触发范围(招式自管,圆形)")]
|
||
[Tooltip("触发半径(m);category==Attack 时必须 > 0,否则永远够不着(Awake 报错)")]
|
||
[Min(0f)] public float rangeRadius = 0f;
|
||
[Tooltip("范围圆心相对敌人的偏移(m),X 随朝向翻转")]
|
||
public Vector2 rangeOffset = Vector2.zero;
|
||
|
||
/// <summary>SOValidationRunner 自动扫描调用:校验 Attack 类招式必须配置有效射程。</summary>
|
||
public IEnumerable<ValidationResult> Validate()
|
||
{
|
||
if (category == AbilityCategory.Attack && rangeRadius <= 0f)
|
||
yield return ValidationResult.Error(
|
||
$"能力 \"{abilityId}\" category=Attack 但 rangeRadius<=0,攻击选择器永远选不中该招式,请补齐 rangeRadius。");
|
||
}
|
||
}
|
||
}
|