Files
zeling_v2/Assets/_Game/Scripts/Enemies/FlyingEnemy.cs
T
joywayerandClaude Opus 5 cf0ac60fad refactor(enemy): 清全库行为树残留,删无人使用的 Boss 技能事件频道
Task 21 Step 2 全库扫描后的收尾:

注释与 Tooltip 里的旧决策层措辞逐处改为只描述功能——
EnemyControlledState / RangedEnemy / FlyingEnemy / SensorSlotNames /
EnemyPoiseComponent / EnemyAnimationConfigSO / EnemyAiBrain。

EnemyQuotaManager 的序列化字段 _maxActiveBehaviorTrees 改名 _maxActiveBrains
(它裁剪的实际是 EnemyAiBrain),带 FormerlySerializedAs。复核确认目前
无任何场景 / 预制体挂载该组件,故无值可丢;属未雨绸缪。

BossSkillEventChannelSO + BossEvents.BossSkillEvent + EVT_BossSkill.asset 删除:
唯一发送方 BossSkillExecutor 已随旧轨删除,复核确认全项目零发送方、零订阅方,
资产 guid 在场景 / 预制体 / Addressables 分组中均无引用。

自检:编译 0 error;EditMode 260/260 通过;
SO 校验 0 error 0 warning;层矩阵 25/25 正确。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 17:14:09 +08:00

79 lines
2.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.Generic;
using UnityEngine;
using BaseGames.Combat;
namespace BaseGames.Enemies
{
/// <summary>
/// 飞行敌人基类。
///
/// 导航由 <see cref="Navigation.FlyingNavigator"/> 实现(IEnemyNavigator),
/// AI 决策由挂载的 <see cref="EnemyAiBrain"/>BrainGraph)驱动。
/// 本类仅负责:
/// <list type="bullet">
/// <item>Rigidbody2D 无重力初始化</item>
/// <item>接触伤害(OnTriggerStay2D</item>
/// <item>StopMovement / MoveInDirection 的 Rigidbody2D 快速移动重写</item>
/// </list>
/// </summary>
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<HurtBox, float> _contactTimers = new();
protected override void Awake()
{
base.Awake();
_rb = GetComponent<Rigidbody2D>();
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<HurtBox>();
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);
}
}
}