Files
Gen_Hack-and-Slash-Roguelite/Client/Assets/Scripts/Entity/Hediff.cs

277 lines
10 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using System.Linq;
using Data;
using UnityEngine;
namespace Entity
{
/// <summary>
/// 定义一个接口,用于提供属性偏移量。
/// 任何实现此接口的组件都可以贡献实体的属性修正。
/// </summary>
public interface IAttributesOffsetProvider
{
/// <summary>
/// 获取此提供者当前的属性偏移量定义。
/// </summary>
/// <returns>此提供者所带来的属性偏移量。</returns>
AttributesOffsetDef GetAttributesOffset();
}
/// <summary>
/// 表示一个实体上运行时存在的健康状态Hediff
/// Hediff 可以是疾病、增益、减益、伤口等,它们会影响实体的属性、行为或状态。
/// </summary>
public class Hediff
{
/// <summary>
/// 此 Hediff 的定义数据。
/// </summary>
public HediffDef def { get; private set; }
/// <summary>
/// 此 Hediff 附加到的活体实体。
/// </summary>
public LivingEntity parent { get; internal set; }
/// <summary>
/// 此 Hediff 存在的当前年龄(以秒为单位)。
/// </summary>
public float Age { get; private set; } = 0f;
/// <summary>
/// 当前激活的 Hediff 阶段的索引。
/// </summary>
private int _currentStageIndex = -1;
/// <summary>
/// 附加到此 Hediff 上的所有组件列表。
/// </summary>
public List<HediffComp> Comps { get; private set; } = new List<HediffComp>();
/// <summary>
/// 标志,指示此 Hediff 是否应该被父实体移除。
/// </summary>
public bool ShouldRemove { get; private set; } = false;
/// <summary>
/// 内部缓存,用于存储计算出的总属性偏移量。
/// </summary>
private AttributesOffsetDef _cachedTotalAttributesOffset;
/// <summary>
/// 标志,指示 Hediff 的属性偏移量是否需要重新计算。
/// </summary>
private bool _attribsDirty = true;
/// <summary>
/// 构造函数,创建一个新的运行时 Hediff 实例。
/// </summary>
/// <param name="definition">此 Hediff 的定义。</param>
/// <exception cref="ArgumentNullException">如果传入的定义为空。</exception>
public Hediff(HediffDef definition)
{
if (definition == null)
{
throw new ArgumentNullException(nameof(definition), "Hediff 定义不能为空。");
}
this.def = definition;
this._attribsDirty = true; // 构造时标记需要计算属性
// 确保阶段列表按开始时间排序,以便正确判断当前阶段。
if (this.def.stages == null) this.def.stages = new List<HediffStageDef>();
this.def.stages = this.def.stages.OrderBy(s => s.start).ToList();
// 实例化所有定义的组件。
if (def.comps != null)
{
foreach (var compDef in def.comps)
{
if (compDef.compClass != null && typeof(HediffComp).IsAssignableFrom(compDef.compClass))
{
try
{
// 使用 Activator.CreateInstance 动态创建组件实例,并传入构造函数参数。
// HediffComp 的构造函数需要接受 Hediff parentHediff 和 HediffCompDef def。
var comp = (HediffComp)Activator.CreateInstance(compDef.compClass, this, compDef);
Comps.Add(comp);
comp.Initialize(); // 初始化组件
}
catch (Exception ex)
{
Debug.LogError(
$"实例化健康状态组件 '{compDef.compClass?.Name ?? ""}' 失败,所属健康状态 '{def.defName ?? def.GetType().Name}'{ex.Message}");
}
}
else
{
Debug.LogWarning(
$"警告:健康状态组件定义 '{compDef.compClass?.Name ?? ""}' 无效或未继承自 HediffComp所属健康状态 '{def.defName ?? def.GetType().Name}'。");
}
}
}
// 初始化时确定第一个阶段,这会触发 SetDirty()。
UpdateStageIndex();
}
/// <summary>
/// 获取此 Hediff 当前激活的阶段定义。
/// 如果没有激活的阶段或阶段列表为空,则返回 null。
/// </summary>
public HediffStageDef CurrentStage
{
get
{
if (_currentStageIndex >= 0 && _currentStageIndex < def.stages.Count)
{
return def.stages[_currentStageIndex];
}
return null;
}
}
/// <summary>
/// 获取此 Hediff 当前累计的总属性偏移量。
/// 只有当属性被标记为“脏”时才重新计算,否则返回缓存值。
/// </summary>
public AttributesOffsetDef CurrentTotalAttributesOffset
{
get
{
// 只有当属性需要更新时才重新计算。
if (_attribsDirty || _cachedTotalAttributesOffset == null)
{
_cachedTotalAttributesOffset = CalculateTotalAttributesOffset();
_attribsDirty = false; // 计算完成后重置标志。
}
return _cachedTotalAttributesOffset;
}
}
/// <summary>
/// 内部方法,用于实际计算 Hediff 的所有总属性偏移量。
/// 这包括当前阶段的偏移量和所有组件提供的偏移量。
/// </summary>
/// <returns>此 Hediff 当前的总属性偏移量。</returns>
private AttributesOffsetDef CalculateTotalAttributesOffset()
{
var totalOffset = new AttributesOffsetDef();
if (CurrentStage != null)
{
totalOffset += CurrentStage.attributesOffset;
}
// 累加来自组件的属性偏移。
foreach (var comp in Comps)
{
if (comp is IAttributesOffsetProvider attributesOffsetProvider)
{
totalOffset += attributesOffsetProvider.GetAttributesOffset();
}
}
return totalOffset;
}
/// <summary>
/// 标记 Hediff 的属性偏移量需要重新计算。
/// 当 Hediff 的内部状态改变并可能影响属性时调用。
/// 同时会通知其父 LivingEntity使其也更新属性缓存。
/// </summary>
internal void SetDirty()
{
_attribsDirty = true;
// 如果此 Hediff 附加到了一个 LivingEntity 上,也通知 LivingEntity 属性可能改变。
if (parent)
{
parent.SetAttribsDirty();
}
}
/// <summary>
/// 更新 Hediff 的年龄,检查阶段变化并更新所有组件。
/// </summary>
/// <param name="deltaTime">自上次更新以来的时间(秒)。</param>
public void Tick(float deltaTime)
{
if (ShouldRemove)
return; // 已经标记为移除,无需继续更新。
Age += deltaTime; // 增加 Hediff 的年龄。
UpdateStageIndex(); // 检查是否有阶段变化(此方法内部会调用 SetDirty
// 更新所有组件。
foreach (var comp in Comps)
{
comp.Tick(deltaTime);
}
// 检查 Hediff 是否到期(如果 def.time > 0 表示有时限,否则为永久)。
if (def.time > 0 && Age >= def.time)
{
ShouldRemove = true;
SetDirty(); // Hediff 将被移除,其贡献的属性将不再有效,标记为脏。
}
}
/// <summary>
/// 根据当前年龄更新阶段索引。
/// 如果阶段发生变化,会调用 SetDirty()。
/// </summary>
private void UpdateStageIndex()
{
var originalStageIndex = _currentStageIndex; // 获取当前阶段索引。
var newStageIndex = _currentStageIndex;
// 从后往前遍历阶段,找到当前年龄所属的最高阶段。
for (var i = def.stages.Count - 1; i >= 0; i--)
{
if (def.stages[i].start <= Age)
{
newStageIndex = i;
break;
}
}
// 如果阶段发生变化,则标记为脏。
if (newStageIndex != originalStageIndex)
{
_currentStageIndex = newStageIndex;
// 阶段发生变化,属性偏移可能改变,标记为脏。
SetDirty();
}
}
/// <summary>
/// 当此 Hediff 被添加到实体时调用。
/// 进行初始化设置,如存储父实体引用,并标记属性为脏以强制重新计算。
/// </summary>
/// <param name="entity">此 Hediff 附加到的 LivingEntity 实例。</param>
internal void OnAdded(LivingEntity entity)
{
this.parent = entity; // 存储父实体引用。
SetDirty(); // 刚添加也需要标记为脏以确保属性在下次计算时被纳入。
foreach (var comp in Comps)
{
comp.OnAdded();
}
}
/// <summary>
/// 当此 Hediff 从实体移除时调用。
/// 进行清理操作,如清除父实体引用,并标记属性为脏以强制重新计算。
/// </summary>
/// <param name="entity">此 Hediff 从中移除的 LivingEntity 实例。</param>
internal void OnRemoved(LivingEntity entity)
{
foreach (var comp in Comps)
{
comp.OnRemoved();
}
this.parent = null; // 清除对父实体的引用。
SetDirty(); // 移除后也需要标记为脏确保属性计算考虑去除此Hediff。
}
}
}