Files
zeling_v2/Assets/_Game/Scripts/Enemies/EnemyStats.cs
Joywayer a1b4e629aa feat: Implement Room Streaming System
- Add RoomStreamingManager to manage room loading and unloading based on player proximity.
- Create StreamingBudgetConfigSO for memory and performance budgeting of the streaming system.
- Introduce TransitionDirector to handle seamless and atmospheric fade transitions between rooms.
- Develop WorldGraph to represent room connectivity and facilitate neighbor queries and distance calculations.
- Implement RoomNode and RoomEdge classes to structure room data and connections.
2026-05-23 19:10:29 +08:00

96 lines
3.6 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 UnityEngine;
using BaseGames.Core;
using BaseGames.Core.Events;
namespace BaseGames.Enemies
{
/// <summary>
/// 敌人运行时数值组件(架构 07_EnemyModule §2
/// 由 EnemyBase.Awake() 通过 Initialize(EnemyStatsSO) 注入配置。
/// 同时订阅难度变更事件,支持游戏进行中切换难度(架构 19 §5
/// </summary>
public class EnemyStats : MonoBehaviour
{
private EnemyStatsSO _config;
[SerializeField] private DifficultyChangedEventChannel _onDifficultyChanged;
public int MaxHP { get; private set; }
public int CurrentHP { get; private set; }
public int Defense { get; private set; }
public float AttackCooldownTimer { get; private set; }
// ── 移动速度(透传 SO供 BD 任务运行时读取)────────────────────────
public float WalkSpeed => _config?.WalkSpeed ?? 2f;
public float RunSpeed => _config?.RunSpeed ?? 4f;
// ── AI 追击配置(透传 SO──────────────────────────────────────────
public float MaxChaseDistance => _config?.MaxChaseDistance ?? 15f;
public float LoseLinkTimeout => _config?.LoseLinkTimeout ?? 2f;
public float AlertDuration => _config?.AlertDuration ?? 0.6f;
public float InvestigateDuration => _config?.InvestigateDuration ?? 3f;
public float HomeRadius => _config?.HomeRadius ?? 0.5f;
/// <summary>
/// 每帧由 EnemyBase 更新sqrMagnitude避免 sqrt 开销)。
/// 使用方请与 range*range 比较,而非直接与 range 比较。
/// </summary>
public float SqrDistanceToPlayer { get; set; }
private readonly CompositeDisposable _subs = new();
private void OnEnable()
{
_onDifficultyChanged?.Subscribe(HandleDifficultyChanged).AddTo(_subs);
}
private void OnDisable()
{
_subs.Clear();
}
public void Initialize(EnemyStatsSO so)
{
_config = so;
Defense = so.Defense; // Defense 不随难度缩放(架构 19 §5
ApplyHPScaler();
CurrentHP = MaxHP;
}
/// <summary>难度变更时重算 HP保持 HP 比例,架构 19 §5。</summary>
private void HandleDifficultyChanged(DifficultyLevel _)
{
if (_config == null) return;
float hpRatio = MaxHP > 0 ? (float)CurrentHP / MaxHP : 1f;
ApplyHPScaler();
CurrentHP = Mathf.Clamp(Mathf.RoundToInt(MaxHP * hpRatio), 1, MaxHP);
}
private void ApplyHPScaler()
{
if (_config == null) return;
var scaler = ServiceLocator.GetOrDefault<IDifficultyService>()?.CurrentScaler;
int raw = scaler != null
? Mathf.RoundToInt(_config.MaxHP * scaler.EnemyHPMultiplier)
: _config.MaxHP;
MaxHP = Mathf.Max(1, raw); // 防止 MaxHP=0 导致 HP 比例计算 NaN
}
public void TakeDamage(int amount)
{
CurrentHP = Mathf.Max(0, CurrentHP - amount);
}
public void TickAttackCooldown(float dt)
{
if (AttackCooldownTimer > 0f)
AttackCooldownTimer -= dt;
}
public void ResetAttackCooldown()
{
AttackCooldownTimer = _config.AttackCooldown;
}
}
}