Files
zeling_v2/Assets/_Game/Scripts/Enemies/Abilities/AnimatedCeilingDropAbility.cs
T

81 lines
2.8 KiB
C#

using System.Collections;
using Animancer;
using BaseGames.AI;
using UnityEngine;
namespace BaseGames.Enemies.Abilities
{
/// <summary>
/// 带动画的天花板跌落能力:播放 Fall 动画 + 切换物理体为 Dynamic 自由下落,落地后启用接触伤害并恢复巡逻。
/// 取代 sealed 的 CeilingDropAbility,动画所有权完整封装在本能力中。
/// 可复用于任何需要从天花板落下并造成接触伤害的敌人。
/// </summary>
[RequireComponent(typeof(Rigidbody2D))]
public class AnimatedCeilingDropAbility : EnemyAbilityBase
{
[Header("落地后")]
[SerializeField] private BodyContactDamage _contactDamage;
private AnimatedCeilingDropAbilitySO _cfg;
private Rigidbody2D _rb;
protected override void Awake()
{
base.Awake();
_cfg = ResolveConfig<AnimatedCeilingDropAbilitySO>();
_rb = GetComponentInParent<Rigidbody2D>();
}
protected override IEnumerator ExecuteCoroutine()
{
if (_cfg == null) yield break;
Phase = AbilityRunState.Active;
// 播放下落动画(能力脚本负责动画所有权)
if (_cfg.fallLoopClip.Clip != null)
_animancer.Play(_cfg.fallLoopClip);
// 切换物理:Kinematic → Dynamic + 重力
var origBodyType = _rb.bodyType;
var origGravScale = _rb.gravityScale;
_rb.bodyType = RigidbodyType2D.Dynamic;
_rb.gravityScale = _cfg.fallGravityScale;
_rb.velocity = Vector2.zero;
// 等待落地(超时保护)
float elapsed = 0f;
while (elapsed < _cfg.maxFallTime)
{
elapsed += Time.fixedDeltaTime;
yield return new WaitForFixedUpdate();
if (elapsed > 0.05f && IsGrounded()) break;
}
_rb.velocity = Vector2.zero;
// 落地后启用接触伤害
if (_contactDamage != null)
_contactDamage.enabled = true;
yield return EnemyAbilityWaits.Get(_cfg.recoveryTime);
// PlayLocomotionClip(Patrol) 播放 AnimConfig.Walk(地面移动动画)
_enemy.PlayLocomotionClip(LocomotionMode.Patrol);
}
private bool IsGrounded()
{
var hit = Physics2D.Raycast(_rb.position, Vector2.down, 0.6f, _cfg.groundMask);
return hit.collider != null;
}
protected override void OnInterrupted(InterruptReason reason)
{
if (_rb != null)
_rb.velocity = Vector2.zero;
if (_contactDamage != null)
_contactDamage.enabled = false;
}
}
}