BossSkillSO / AttackPatternSO / SkillSequenceSO / BossSkillExecutor / BossSkillTypes / WeakPointSystem / TelegraphSystem / BossSkillModule / BossSkillSequenceWindow,连同 Patterns 独立程序集(BaseGames.Enemies.Boss.Patterns.asmdef, 已核实无任何 asmdef 按名或按 GUID 引用它)整包移除。 删前先清两处引用: - ChaoFengKnockdownCounter 击落打断改走 _boss.Abilities.InterruptAll(ExternalRequest) - EditorScaffoldUtils 命名前缀表删掉两条指向已删类型的死条目(还与 AssetFolderSpec 的 ABL_ 冲突) 判据「有更优替代才删」逐项对应: - 编排 → EnemyAbilitySO + EnemyAttackSO(归一化时机 / 槽位 HitBox) - 阶段门 → BossPhaseAbilityGate - 选招 → EnemyAttackSelector + WeightedRandomAntiRepeat - 可弹反 → DamageSourceSO.Flags(CanBeParried),HurtBox 已在判定 - 弱点倍率 → HurtBox 自带倍率(原实现的 GetDamageMultiplier 零调用者) - 预警 → clip 姿态 + 动画事件(TriggerFeedback / PlaySFX 已补接) - 竞技场联动 → EnemySpawnerOnEvent - 霸体窗口 → EnemyAttackSO.hasPoiseWindow 四字段 能力资产的编辑器总览视图随 BossSkillModule 一并消失, 后续补 EnemyAbilityModule(优先级低于 AiDefinitionValidator)。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
102 lines
3.7 KiB
C#
102 lines
3.7 KiB
C#
using System.Collections;
|
||
using Animancer;
|
||
using BaseGames.Boss;
|
||
using BaseGames.Combat;
|
||
using BaseGames.Enemies.Abilities;
|
||
using UnityEngine;
|
||
|
||
namespace BaseGames.Enemies.Boss
|
||
{
|
||
/// <summary>
|
||
/// 嘲风击落计数器(Phase 2)。
|
||
/// 由 <see cref="ChaoFengBoss.OnDamageTaken"/> 直接调用 <see cref="OnBossHit"/>,
|
||
/// 累计命中达到阈值后触发击落序列(下落 → 硬直 → 复位浮空)。
|
||
///
|
||
/// ⚠️ HurtBox 无公开 OnDamageTaken 事件,必须通过 EnemyBase.OnDamageTaken 虚方法转发。
|
||
/// </summary>
|
||
public class ChaoFengKnockdownCounter : MonoBehaviour
|
||
{
|
||
[SerializeField] private int _threshold = 8;
|
||
|
||
[Header("依赖引用")]
|
||
[SerializeField] private ChaoFengBoss _boss;
|
||
[SerializeField] private ChaoFengFloatController _floatCtrl;
|
||
|
||
[Header("击落动画")]
|
||
[SerializeField] private ClipTransition _knockdownHitClip;
|
||
[Tooltip("击落后硬直动画(复用 Defeat_Pant Clip)")]
|
||
[SerializeField] private ClipTransition _staggerClip;
|
||
|
||
[SerializeField] private float _staggerDuration = 3f;
|
||
|
||
private int _count;
|
||
private bool _inKnockdown;
|
||
private BaseGames.Core.IGroundedActor _playerGround;
|
||
private Transform _cachedPlayer;
|
||
|
||
/// <summary>
|
||
/// 由 <see cref="ChaoFengBoss.OnDamageTaken"/> 调用,累计受击并在达到阈值时触发击落。
|
||
/// 仅统计「玩家处于空中」时的命中(设计:空中攻击命中嘲风才计入击落)。
|
||
/// </summary>
|
||
public void OnBossHit(DamageInfo info)
|
||
{
|
||
if (_inKnockdown || _boss == null || _boss.CurrentPhase != 1) return;
|
||
if (!IsPlayerAirborne()) return; // Q6:仅玩家在空中的命中计数
|
||
|
||
_count++;
|
||
if (_count >= _threshold)
|
||
{
|
||
_count = 0;
|
||
StartCoroutine(KnockdownSequence());
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通过 Boss 缓存的 PlayerTransform 取玩家的 <see cref="BaseGames.Core.IGroundedActor"/>(PlayerMovement 实现),
|
||
/// 判定其是否离地。取不到接口时按「空中」处理(保守计数,避免机制失效)。
|
||
/// </summary>
|
||
private bool IsPlayerAirborne()
|
||
{
|
||
var player = _boss.PlayerTransform;
|
||
if (player == null) return false;
|
||
if (!ReferenceEquals(player, _cachedPlayer))
|
||
{
|
||
_cachedPlayer = player;
|
||
_playerGround = player.GetComponentInParent<BaseGames.Core.IGroundedActor>()
|
||
?? player.GetComponentInChildren<BaseGames.Core.IGroundedActor>();
|
||
}
|
||
return _playerGround == null || !_playerGround.IsGrounded;
|
||
}
|
||
|
||
/// <summary>强制结束正在进行中的击落序列(由 ChaoFengBoss.DefeatSequence 调用)。</summary>
|
||
public void ForceEnd()
|
||
{
|
||
StopAllCoroutines();
|
||
_inKnockdown = false;
|
||
_count = 0;
|
||
}
|
||
|
||
private IEnumerator KnockdownSequence()
|
||
{
|
||
_inKnockdown = true;
|
||
|
||
// 击落打断当前正在执行的所有能力(招式统一由能力注册表管理)
|
||
_boss.Abilities.InterruptAll(InterruptReason.ExternalRequest);
|
||
|
||
if (_knockdownHitClip.Clip != null)
|
||
_boss.Animancer.Play(_knockdownHitClip);
|
||
|
||
yield return _floatCtrl.FallDown();
|
||
|
||
if (_staggerClip.Clip != null)
|
||
_boss.Animancer.Play(_staggerClip);
|
||
|
||
yield return new WaitForSeconds(_staggerDuration);
|
||
|
||
yield return _floatCtrl.FloatUp();
|
||
|
||
_inKnockdown = false;
|
||
}
|
||
}
|
||
}
|