using System.Collections.Generic; using UnityEngine; using BaseGames.Combat; namespace BaseGames.Enemies { /// /// 飞行敌人基类。 /// /// 导航由 实现(IPathAgent), /// AI 行为逻辑由挂载的 Behavior Designer 树驱动。 /// 本类仅负责: /// /// Rigidbody2D 无重力初始化 /// 接触伤害(OnTriggerStay2D) /// StopMovement / MoveInDirection 的 Rigidbody2D 快速移动重写 /// /// public class FlyingEnemy : EnemyBase { [Header("飞行移动(快速覆盖速度)")] [SerializeField] private float _moveSpeed = 3f; [Header("接触伤害")] [SerializeField] private DamageSourceSO _contactDamageSource; [Tooltip("对停留在体接触范围内的同一目标重复造成伤害的间隔(秒)。")] [SerializeField] private float _contactInterval = 0.5f; private Rigidbody2D _rb; // 按目标节流:避免 OnTriggerStay2D 每个物理帧都造成伤害(与 HitBox.Interval 节奏一致) private readonly Dictionary _contactTimers = new(); protected override void Awake() { base.Awake(); _rb = GetComponent(); if (_rb != null) { _rb.gravityScale = 0f; _rb.constraints = RigidbodyConstraints2D.FreezeRotation; } } public override void StopMovement() { if (_rb != null) _rb.velocity = Vector2.zero; } public override void MoveInDirection(float dir) { if (_rb != null) _rb.velocity = new Vector2(dir * _moveSpeed, 0f); } private void OnTriggerStay2D(Collider2D other) { if (_contactDamageSource == null) return; if (CurrentState == EnemyStateType.Dead) return; if (_rb == null) return; var hurtBox = other.GetComponent(); if (hurtBox == null) return; // 按目标间隔节流:停留接触时每 _contactInterval 秒最多结算一次, // 不再每个物理帧都调用 ReceiveDamage(命中是否生效仍由承伤方无敌帧决定)。 float now = Time.time; if (_contactTimers.TryGetValue(hurtBox, out float last) && now - last < _contactInterval) return; _contactTimers[hurtBox] = now; Vector2 knockDir = ((Vector2)other.bounds.center - _rb.position).normalized; var info = DamageInfo.From( _contactDamageSource, knockDir, transform.position, gameObject.layer); hurtBox.ReceiveDamage(info); } } }