Merge branch 'temp827'

This commit is contained in:
m0_75251201
2025-09-03 19:57:08 +08:00
208 changed files with 16296 additions and 2228 deletions

View File

@ -1,3 +1,4 @@
using System;
using Data;
namespace Entity
@ -8,9 +9,10 @@ namespace Entity
public float moveSpeed = 1;
public int attack = 1;
public int defense = 0;
public int attackSpeed = 2;
public int attackRange = 3;
public float attackSpeed = 2;
public float attackRange = 3;
public int attackTargetCount = 1;
public Attributes(AttributesDef def)
{
health = def.health;
@ -21,7 +23,108 @@ namespace Entity
attackRange = def.attackRange;
attackTargetCount = def.attackTargetCount;
}
public Attributes(Attributes other)
{
health = other.health;
moveSpeed = other.moveSpeed;
attack = other.attack;
defense = other.defense;
attackSpeed = other.attackSpeed;
attackRange = other.attackRange;
attackTargetCount = other.attackTargetCount;
}
public Attributes()
{ }
{
}
/// <summary>
/// 根据给定的属性偏移,生成一个新的 Attributes 实例。
/// 原有的 Attributes 实例保持不变。
/// </summary>
/// <param name="offset">要应用的属性偏移定义。</param>
/// <returns>一个新的 Attributes 实例,包含了应用偏移后的值。</returns>
public Attributes GetModifiedAttributes(AttributesOffsetDef offset)
{
// 1. 创建当前 Attributes 实例的一个副本
var newAttributes = new Attributes(this);
if (offset == null)
{
return newAttributes; // 如果没有偏移,直接返回副本
}
// 2. 在副本上应用绝对值偏移
newAttributes.health += (int)offset.healthOffset;
newAttributes.moveSpeed += offset.moveSpeedOffset;
newAttributes.attack += (int)offset.attackOffset;
newAttributes.defense += (int)offset.defenseOffset;
// 修正: attackSpeed 和 attackRange 是 float不应强制转换为 int
newAttributes.attackSpeed += offset.attackSpeedOffset;
newAttributes.attackRange += offset.attackRangeOffset;
newAttributes.attackTargetCount += (int)offset.attackTargetCountOffset;
// 3. 在副本上应用百分比偏移 (基于应用绝对值偏移后的结果)
newAttributes.health = (int)(newAttributes.health * (1 + offset.healthPercentOffset));
newAttributes.moveSpeed *= (1 + offset.moveSpeedPercentOffset);
newAttributes.attack = (int)(newAttributes.attack * (1 + offset.attackPercentOffset));
newAttributes.defense = (int)(newAttributes.defense * (1 + offset.defensePercentOffset));
// 修正: attackSpeed 和 attackRange 是 float不应强制转换为 int
newAttributes.attackSpeed *= (1 + offset.attackSpeedPercentOffset);
newAttributes.attackRange *= (1 + offset.attackRangePercentOffset);
newAttributes.attackTargetCount =
(int)(newAttributes.attackTargetCount * (1 + offset.attackTargetCountPercentOffset));
// 4. 确保属性不低于最小值
newAttributes.health = Math.Max(0, newAttributes.health);
newAttributes.moveSpeed = Math.Max(0f, newAttributes.moveSpeed);
newAttributes.attack = Math.Max(0, newAttributes.attack);
newAttributes.defense = Math.Max(0, newAttributes.defense);
// 修正: Math.Max 期望相同类型0f 对于 float 类型更准确
newAttributes.attackSpeed = Math.Max(0f, newAttributes.attackSpeed);
newAttributes.attackRange = Math.Max(0f, newAttributes.attackRange);
newAttributes.attackTargetCount = Math.Max(1, newAttributes.attackTargetCount);
// 5. 返回修改后的新 Attributes 实例
return newAttributes;
}
/// <summary>
/// 合并两个 Attributes 实例,生成一个新的 Attributes 实例,
/// 其中每个属性值都取自传入两个实例中对应属性的最小值。
/// 这对于应用属性上限或限制非常有用。
/// </summary>
/// <param name="a">第一个 Attributes 实例。</param>
/// <param name="b">第二个 Attributes 实例。</param>
/// <returns>一个新的 Attributes 实例,其属性是输入实例中对应属性的最小值。</returns>
public static Attributes Min(Attributes a, Attributes b)
{
// 处理 null 情况
if (a == null && b == null) return new Attributes(); // 两者都为null返回默认空属性
if (a == null) return new Attributes(b); // a为null返回b的副本
if (b == null) return new Attributes(a); // b为null返回a的副本
// 创建一个新的 Attributes 实例来存储结果
var result = new Attributes
{
health = Math.Min(a.health, b.health),
moveSpeed = Math.Min(a.moveSpeed, b.moveSpeed),
attack = Math.Min(a.attack, b.attack),
defense = Math.Min(a.defense, b.defense),
attackSpeed = Math.Min(a.attackSpeed, b.attackSpeed),
attackRange = Math.Min(a.attackRange, b.attackRange),
attackTargetCount = Math.Min(a.attackTargetCount, b.attackTargetCount)
};
return result;
}
}
}
}

View File

@ -5,7 +5,7 @@ using UnityEngine;
namespace Entity
{
public class Character : Entity
public class Character : LivingEntity
{
private int _currentSelected; // 私有字段用于存储实际值
@ -21,6 +21,7 @@ namespace Entity
var maxIndex = Inventory != null && Inventory.Capacity > 0 ? Inventory.Capacity - 1 : 0;
var clampedValue = Mathf.Clamp(value, 0, maxIndex);
_currentSelected = clampedValue;
InitWeaponAnimator();
}
}
@ -64,29 +65,6 @@ namespace Entity
return remainingQuantity;
}
// public override void TryAttack()
// {
// if (IsAttacking)
// return;
// if (!DefineManager.Instance.defines.TryGetValue(nameof(BulletDef), out var def))
// return;
// // 修正First() 可能会在一个空的 Values 集合上抛出异常。
// // 更好的做法是使用 TryGetValue 或 FirstOrDefault 并检查结果。
// // 这里假设至少有一个 BulletDef 存在,如果不是,需要更复杂的错误处理。
// var bulletDefEntry = def.Values.FirstOrDefault();
// if (bulletDefEntry == null)
// {
// Debug.LogError("No BulletDef found in DefineManager. Cannot attack.");
// return;
// }
//
// var bulletDef = (BulletDef)bulletDefEntry;
//
// Vector3 dir = MousePosition.GetWorldPosition();
// EntityManage.Instance.GenerateBulletEntity(Program.Instance.FocusedDimensionId, bulletDef, Position,
// dir - Position, this);
// }
public override WeaponResource GetCurrentWeapon()
{
var currentSelectItem = Inventory.GetSlot(CurrentSelected);

View File

@ -32,6 +32,12 @@ namespace Entity
public EntityPrefab entityPrefab;
public EntityDef entityDef;
/// <summary>
/// 手上拿着显示的贴图
/// </summary>
public GameObject weaponAnimator;
public ITick[] weaponAnimatorNodeList;
/// <summary>
/// 人工智能行为树,定义实体的行为逻辑。
@ -46,7 +52,13 @@ namespace Entity
/// <summary>
/// 实体的属性定义,包括生命值、攻击力、防御力等。
/// </summary>
public Attributes attributes = new();
public virtual Attributes attributes { get; protected set; }
private Attributes _baseAttributes;
public virtual Attributes baseAttributes
{
get { return _baseAttributes ??= new Attributes(entityDef.attributes); }
}
/// <summary>
/// 实体当前的移动方向。
@ -164,7 +176,6 @@ namespace Entity
private Coroutine _attackCoroutine;
[SerializeField] private float _hitBarUIShowTime = 5;
private float _hitBarUIShowTimer = 0;
private int _walkingTimer = 0;
@ -183,13 +194,34 @@ namespace Entity
this.entityDef = entityDef;
HideHealthBar();
InitWeaponAnimator();
}
protected virtual void InitWeaponAnimator()
{
if (!weaponAnimator)
return;
for (var i = 0; i < weaponAnimator.transform.childCount; i++)
{
Destroy(weaponAnimator.transform.GetChild(i).gameObject);
weaponAnimatorNodeList = null;
}
var weapon = GetCurrentWeapon();
if (weapon == null)
{
weaponAnimator.SetActive(false);
return;
}
var weaponAnimation = weapon.InstantiateAttackAnimation(weaponAnimator.transform);
weaponAnimatorNodeList = weaponAnimation.animationComponents;
}
/// <summary>
/// 初始化实体的身体部分,包括不同朝向下的绘图节点。
/// </summary>
/// <param name="drawingOrder">绘制顺序定义。</param>
public virtual void InitBody(DrawingOrderDef drawingOrder)
protected virtual void InitBody(DrawingOrderDef drawingOrder)
{
// 预缓存枚举值(避免每次循环重复调用 Enum.GetValues
var states = Enum.GetValues(typeof(EntityState)).Cast<EntityState>().ToArray();
@ -295,7 +327,7 @@ namespace Entity
/// <param name="drawNode">绘图节点定义。</param>
/// <param name="parent">父节点对象。</param>
/// <returns>创建的GameObject如果失败则返回null</returns>
public virtual GameObject InitBodyPart(DrawNodeDef drawNode, GameObject parent)
protected virtual GameObject InitBodyPart(DrawNodeDef drawNode, GameObject parent)
{
try
{
@ -434,7 +466,7 @@ namespace Entity
/// <summary>
/// 更新实体的逻辑,包括玩家控制和自动行为。
/// </summary>
public void Tick()
public virtual void Tick()
{
if (_walkingTimer > 0)
{
@ -470,6 +502,13 @@ namespace Entity
}
}
if (weaponAnimatorNodeList != null)
{
foreach (var tick in weaponAnimatorNodeList)
{
tick.Tick();
}
}
if (IsShowingHealthBarUI)
{
_hitBarUIShowTimer -= Time.deltaTime;
@ -488,14 +527,12 @@ namespace Entity
if (IsAttacking || IsDead) return; // 死亡时无法攻击
// 尝试获取当前武器
WeaponResource currentWeapon = GetCurrentWeapon();
var currentWeapon = GetCurrentWeapon();
// 如果没有武器,可以选择进行徒手攻击或者直接返回
// 暂时设定为:如果没有武器,则不进行攻击
if (currentWeapon == null)
{
// 可以在这里添加一个默认的徒手攻击逻辑,或者播放一个“不能攻击”的提示
Debug.Log($"{name} 没有装备武器,无法攻击。");
return;
}
@ -744,7 +781,7 @@ namespace Entity
}
// STEP 4: 等待到攻击判定时间
float elapsedTime = 0f;
var elapsedTime = 0f;
while (elapsedTime < weapon.AttackDetectionTime)
{
if (IsDead)
@ -766,7 +803,7 @@ namespace Entity
ExecuteWeaponAction(weapon);
float remainingAnimationTime = weapon.AttackAnimationTime - elapsedTime;
var remainingAnimationTime = weapon.AttackAnimationTime - elapsedTime;
if (remainingAnimationTime > 0)
{
yield return new WaitForSeconds(remainingAnimationTime);
@ -851,10 +888,10 @@ namespace Entity
// 获取子弹方向。这里使用实体当前的移动方向作为子弹发射方向
// 更复杂的逻辑可能根据鼠标位置、目标位置等确定
Vector3 bulletDirection = direction; // 实体当前的朝向
var bulletDirection = direction; // 实体当前的朝向
if (PlayerControlled && Input.GetMouseButton(0)) // 玩家控制时,如果鼠标按下,尝试朝鼠标方向发射
{
Vector3 mouseWorldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
var mouseWorldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
mouseWorldPos.z = transform.position.z; // 保持Z轴一致
bulletDirection = (mouseWorldPos - transform.position).normalized;
}

View File

@ -0,0 +1,276 @@
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。
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: afec36ba23b944cf94ca944a8f8f35f4
timeCreated: 1756308924

View File

@ -0,0 +1,47 @@
using Data;
namespace Entity
{
// 运行时健康状态组件的抽象基类
public abstract class HediffComp
{
protected Hediff parentHediff; // 对父 Hediff 的引用
protected HediffCompDef def; // 对组件定义的引用
public HediffComp(Hediff parentHediff, HediffCompDef def)
{
this.parentHediff = parentHediff;
this.def = def;
}
/// <summary>
/// 组件初始化时调用,在构造函数之后。
/// </summary>
public virtual void Initialize()
{
}
/// <summary>
/// 每帧更新时调用。
/// </summary>
/// <param name="deltaTime">自上次更新以来的时间(秒)。</param>
public virtual void Tick(float deltaTime)
{
}
/// <summary>
/// 当其父 Hediff 被添加到实体时调用。
/// </summary>
public virtual void OnAdded()
{
}
/// <summary>
/// 当其父 Hediff 从实体移除时调用。
/// </summary>
public virtual void OnRemoved()
{
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f3f6a16d500840bea821c21ea612a5c6
timeCreated: 1756612166

View File

@ -0,0 +1,162 @@
using System;
using System.Collections.Generic;
using Data;
using Managers;
using UnityEngine;
namespace Entity
{
// 假设 Entity 基类如下结构
// public abstract class Entity
// {
// public virtual Attributes baseAttributes { get; protected set; } = new Attributes();
// public virtual Attributes attributes { get; protected set; } = new Attributes();
// public virtual void Tick(float deltaTime) { /* Base entity update logic */ }
// }
/// <summary>
/// 表示一个具有生命周期、属性和可受健康状态Hediff影响的实体。
/// </summary>
public class LivingEntity : Entity
{
// 存储应用于此实体的所有健康状态Hediff列表。
protected List<Hediff> hediffs = new List<Hediff>();
// 标记实体属性是否需要重新计算。当Hediff发生变化时此标记会被设置为true。
private bool _needUpdateAttributes = true;
// 缓存实体的基础属性这些属性不受动态Hediff影响但可能受基类或Def影响。
private Attributes _cachedBaseAttributes;
/// <summary>
/// 获取实体的基础属性。这些属性通常来源于实体的定义Def并可能受到常驻的基础健康状态Base Hediffs影响。
/// </summary>
public override Attributes baseAttributes
{
get
{
// 仅在 _cachedBaseAttributes 为 null 时计算一次
if(_cachedBaseAttributes == null)
{
var defAttributes = base.baseAttributes;
var hediffOffset = new AttributesOffsetDef();
// 这里假设 SaveManager.Instance.baseHediffs 指的是“所有实体共通的基础Hediff”
// 并且这些基础 Hediff 也会影响 baseAttributes
foreach (var hediff in SaveManager.Instance.baseHediffs)
{
hediffOffset += hediff.CurrentTotalAttributesOffset;
}
_cachedBaseAttributes = defAttributes.GetModifiedAttributes(hediffOffset);
}
return _cachedBaseAttributes;
}
}
// 缓存实体当前的最终属性该属性是基础属性加上所有健康状态Hediff修正后的结果。
private Attributes _cachedAttributes;
/// <summary>
/// 获取实体当前的最终属性包括所有健康状态Hediff的修正。
/// </summary>
public override Attributes attributes
{
get
{
if (_needUpdateAttributes || _cachedAttributes == null)
{
// 1. 获取旧的属性值(在重新计算之前,也就是当前的缓存值)
// 仅用于需要与“当前值”进行比较或钳制的情况例如最大生命值Buff移除时
var oldCachedAttributes = _cachedAttributes;
if (oldCachedAttributes == null) // 如果是第一次计算初始化一个默认值或者使用baseAttributes
{
oldCachedAttributes = baseAttributes;
}
// 2. 计算完全修正后的“理论”最大属性值(基于 baseAttributes 和所有 Hediff 偏移)
var totalModifiedAttributes = baseAttributes;
var hediffOffset = new AttributesOffsetDef();
foreach (var hediff in hediffs)
{
hediffOffset += hediff.CurrentTotalAttributesOffset;
}
// 应用所有 hediff 的偏移到 totalModifiedAttributes
totalModifiedAttributes = totalModifiedAttributes.GetModifiedAttributes(hediffOffset);
_cachedAttributes = Attributes.Min(oldCachedAttributes, totalModifiedAttributes);
// 标记为已更新
_needUpdateAttributes = false;
}
return _cachedAttributes;
}
protected set => _cachedAttributes = value;
}
/// <summary>
/// 供内部使用的属性标记方法。当 Hediff 自身状态改变并影响属性时,通过此方法通知 LivingEntity。
/// </summary>
internal void SetAttribsDirty()
{
_needUpdateAttributes = true;
}
/// <summary>
/// 每帧调用的更新函数,传入时间增量。
/// </summary>
public override void Tick()
{
base.Tick(); // 调用基类的Tick方法
// 遍历并更新所有健康状态从后向前循环以安全地移除已完成的Hediff
for (var i = hediffs.Count - 1; i >= 0; i--)
{
var hediff = hediffs[i];
hediff.Tick(Time.deltaTime); // 调用单个Hediff的Tick方法
// 检查Hediff是否已达到移除条件
if (hediff.ShouldRemove)
{
RemoveHediff(hediff); // 使用RemoveHediff方法确保OnRemoved被调用并设置_needUpdateAttributes
}
}
}
/// <summary>
/// 添加一个新的健康状态到实体上。
/// </summary>
/// <param name="hediff">要添加的 Hediff 实例。</param>
public void AddHediff(Hediff hediff)
{
if (hediff == null)
{
Debug.LogWarning("尝试向活体实体添加一个空的健康状态Hediff。");
return;
}
hediffs.Add(hediff);
// 通知Hediff它被添加到一个实体上进行初始化等操作并传入自身引用
hediff.OnAdded(this);
_needUpdateAttributes = true; // 添加新Hediff需要更新属性缓存
}
/// <summary>
/// 移除一个特定的健康状态。
/// </summary>
/// <param name="hediff">要移除的 Hediff 实例。</param>
public void RemoveHediff(Hediff hediff)
{
if (hediff == null)
{
Debug.LogWarning("尝试从活体实体移除一个空的健康状态Hediff。");
return;
}
// 尝试从列表中移除Hediff
if (hediffs.Remove(hediff))
{
// 通知Hediff它被从实体上移除进行清理等操作并传入自身引用
hediff.OnRemoved(this);
_needUpdateAttributes = true; // 移除Hediff需要更新属性缓存
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 440140899cba41b3a023f86e27e69909
timeCreated: 1756632414

View File

@ -4,7 +4,7 @@ using Managers;
namespace Entity
{
public class Monster : Entity
public class Monster:LivingEntity
{
private WeaponResource weapon;
public override void Init(EntityDef entityDef)