(client) feat:添加临时动画组件,添加逃跑逻辑

This commit is contained in:
m0_75251201
2025-09-06 12:25:55 +08:00
parent f43aeffebf
commit 15cdd2b244
73 changed files with 3420 additions and 6055 deletions

View File

@ -132,7 +132,7 @@ namespace Managers
foreach (var entityPrefab in currentEntities)
{
// 检查实体预制体或其内部实体是否已销毁或死亡。
if (entityPrefab == null || entityPrefab.entity == null || entityPrefab.entity.IsDead)
if (!entityPrefab || !entityPrefab.entity || entityPrefab.entity.IsDead)
{
entitiesToRemove.Add(entityPrefab);
}
@ -196,7 +196,6 @@ namespace Managers
// 或者 OnSceneLoaded 时 Program 中没有这个维度,但在游戏运行中被注册了。
_dimensionFactionEntities[dimensionId] = new Dictionary<string, LinkedList<EntityPrefab>>();
_dimensionLayerCache[dimensionId] = new Dictionary<string, Transform>();
Debug.LogWarning($"实体管理器:在处理待添加实体时,按需为维度 '{dimensionId}' 初始化内部数据结构。");
}
var factionDict = _dimensionFactionEntities[dimensionId];
@ -470,7 +469,7 @@ namespace Managers
bulletDef,
entityComponent =>
{
if (entityComponent != null && entityComponent.entity != null)
if (entityComponent && entityComponent.entity)
{
entityComponent.entity.SetTarget(pos + dir);
}
@ -481,14 +480,15 @@ namespace Managers
}
);
if (result != null && result.entity is Bullet bullet)
if (result && result.entity is Bullet bullet)
{
bullet.bulletSource = source;
if (source != null) bullet.affiliation = source.affiliation;
if (source) bullet.affiliation = source.affiliation;
}
if (result == null) GenerateDefaultEntity(dimensionId, pos);
if (!result) GenerateDefaultEntity(dimensionId, pos);
}
public void GeneratePickupEntity(string dimensionId, ItemDef itemDef, Vector3 pos)
{
if (!pickupPrefab)
@ -500,32 +500,55 @@ namespace Managers
if (itemDef == null)
{
Debug.LogError("实体管理器itemDef 为空!无法生成子弹。");
// --- 逻辑修改点 1更正错误信息 ---
Debug.LogError("实体管理器itemDef 为空!无法生成拾取物实体。");
GenerateDefaultEntity(dimensionId, pos);
return;
}
var dimension = Program.Instance.GetDimension(dimensionId);
if (dimension == null)
if (!dimension) // 更安全的检查
{
Debug.LogError($"实体管理器:无法生成实体:维度 '{dimensionId}' 在程序Program中不活跃或未注册。");
return;
}
// 获取或创建实体所属的层级Transform并确保其在维度根下。
var parentLayer = EnsureLayerExists(dimensionId, "DefaultEntityLevel");
if (parentLayer == null)
if (!parentLayer)
{
Debug.LogError($"实体管理器:无法在维度 '{dimensionId}' 中获取或创建实体的父层。");
return;
}
var result = Instantiate(pickupPrefab, pos, Quaternion.identity);
var pickup = result.GetComponent<Pickup>();
var result = GameObject.Instantiate(pickupPrefab.gameObject, pos, Quaternion.identity);
if (!result)
{
Debug.LogError($"实体管理器:无法实例化预制体 '{pickupPrefab.name}'。");
GenerateDefaultEntity(dimensionId, pos);
return;
}
var entityPrefab = result.GetComponent<EntityPrefab>();
if (!entityPrefab)
{
Debug.LogError($"实体管理器:实例化出的拾取物实体 '{pickupPrefab.name}' 缺少 'EntityPrefab' 组件!无法完成初始化。已销毁实例。");
GameObject.Destroy(result); // 清理未正确初始化的实例
return;
}
var pickup = entityPrefab.entity as Pickup; // 使用 as 运算符进行安全类型转换
if (!pickup)
{
Debug.LogError($"实体管理器:实例化出的实体 '{entityPrefab.name}' 的核心实体对象无法转换为 'Pickup' 类型或为空。无法完成初始化。已销毁实例。");
GameObject.Destroy(result); // 清理未正确初始化的实例
return;
}
result.transform.SetParent(parentLayer);
pickup.Init(itemDef);
if (result == null) GenerateDefaultEntity(dimensionId, pos);
_pendingAdditions.Add(Tuple.Create(dimensionId, "default", result));
_pendingAdditions.Add(Tuple.Create(dimensionId, "default", entityPrefab));
}
/// <summary>
/// 在指定维度和位置生成一个默认实体(通常作为回退选项)。
/// </summary>
@ -533,7 +556,7 @@ namespace Managers
/// <param name="pos">生成位置。</param>
public void GenerateDefaultEntity(string dimensionId, Vector3 pos)
{
if (Program.Instance.GetDimension(dimensionId) == null)
if (!Program.Instance.GetDimension(dimensionId))
{
Debug.LogError($"实体管理器:无法生成默认实体:维度 '{dimensionId}' 在程序Program中不活跃或未注册。");
return;
@ -615,7 +638,7 @@ namespace Managers
// 2. 在寻找“最近”实体时,通常指的是 *除了自身以外* 的实体。
// 如果需要包含自身(例如,当 targetRelationship 是 AffiliationManager.Relation.Self 时),
// 可以根据具体需求调整此逻辑,但默认行为是排除自身。
if (currentEntityPrefab == null || currentEntityPrefab.entity == null ||
if (!currentEntityPrefab || !currentEntityPrefab.entity ||
currentEntityPrefab.entity.IsDead || currentEntityPrefab == sourceEntityPrefab)
{
continue;
@ -644,19 +667,36 @@ namespace Managers
/// <summary>
/// 在指定维度中,判断是否存在任何与源实体敌对的活跃实体。
/// 此版本修正了将掉落物或子弹识别为敌对派系的问题,现在只考虑可转换为 CombatantEntity 的实体。
/// </summary>
/// <param name="dimensionId">要搜索的维度ID。</param>
/// <param name="sourceEntityPrefab">作为参照的源实体预制体。</param>
/// <returns>如果存在敌对实体则返回 true否则返回 false。</returns>
/// <returns>如果存在敌对的 CombatantEntity 则返回 true否则返回 false。</returns>
public bool ExistsHostile(string dimensionId, EntityPrefab sourceEntityPrefab)
{
// 参数校验:确保输入参数有效,避免空引用异常。
if (sourceEntityPrefab == null || sourceEntityPrefab.entity == null)
// 使用 Unity 的 null 检查运算符 '!'
if (!sourceEntityPrefab || !sourceEntityPrefab.entity)
{
Debug.LogWarning("实体管理器ExistsHostile 方法中,源实体预制体或其内部实体为空。无法执行搜索。");
return false;
}
// 新增校验:确保源实体自身是一个 CombatantEntity。
// 因为我们现在只关注 CombatantEntity 之间的敌对关系。
var sourceCombatant = sourceEntityPrefab.entity as CombatantEntity;
if (!sourceCombatant) // 使用 Unity 的 null 检查运算符 '!'
{
Debug.LogWarning(
$"实体管理器ExistsHostile 方法中,源实体 '{sourceEntityPrefab.name}' 无法转换为 CombatantEntity 类型。无法有效判断是否存在敌对的活跃实体。");
return false;
}
if (sourceCombatant.IsDead)
{
return false; // 源 CombatantEntity 已经失效,它无法判断敌对实体。
}
// 维度数据存在性检查:验证目标维度是否在实体管理器的内部数据结构中被初始化和管理。
if (!_dimensionFactionEntities.TryGetValue(dimensionId, out var factionDict))
{
@ -664,38 +704,47 @@ namespace Managers
return false;
}
// 关系管理器实例检查:确保 AffiliationManager 可用,它是判断实体关系的核心组件。
var affiliationManager = AffiliationManager.Instance;
if (affiliationManager == null)
{
Debug.LogError("实体管理器ExistsHostile 方法中AffiliationManager 实例为空。无法确定实体关系。");
return false;
}
// 遍历所有实体:遍历维度内的所有派系,再遍历每个派系下的所有实体。
foreach (var factionEntities in factionDict.Values)
{
foreach (var currentEntityPrefab in factionEntities)
{
// 实体有效性及排除源实体自身:
// 1. 排除无效或已死亡的实体。
// 2. 排除源实体自身,避免自身判断为敌对
if (currentEntityPrefab == null || currentEntityPrefab.entity == null ||
currentEntityPrefab.entity.IsDead || currentEntityPrefab == sourceEntityPrefab)
// 1. 排除无效的实体预制体或内部实体。
// 2. 排除已失效的 CombatantEntity
// 3. 排除源实体自身,避免自身判断为敌对。
if (!currentEntityPrefab || !currentEntityPrefab.entity ||
currentEntityPrefab == sourceEntityPrefab) // 源实体自身已被转换为 sourceCombatant 并检查,这里只检查 prefab 引用是否相同
{
continue;
}
// 关系判断:判断当前实体与源实体是否为“敌对”关系
if (affiliationManager.GetRelation(sourceEntityPrefab.entity, currentEntityPrefab.entity) ==
Relation.Hostile)
// 【核心改动】新增类型检查:只有能转换为 CombatantEntity 的实体才会被进一步判断
// 这样可以排除掉落物、子弹等非 CombatantEntity 的实体。
var currentCombatant = currentEntityPrefab.entity as CombatantEntity;
if (!currentCombatant) // 使用 Unity 的 null 检查运算符 '!'
{
return true; // 找到第一个敌对实体即返回 true提高效率
continue; // 如果不是 CombatantEntity则跳过此实体
}
// 检查目标 CombatantEntity 是否已失效(死亡或摧毁)。
// 同理,这里假设 CombatantEntity 包含 IsDead 属性。
// **重要:请确保 CombatantEntity 定义了 IsDead 属性,或者替换为更通用的失效状态属性。**
if (currentCombatant.IsDead)
{
continue; // 目标 CombatantEntity 已经失效,不是活跃的敌对实体。
}
// 关系判断:判断当前 CombatantEntity 与源 CombatantEntity 是否为“敌对”关系。
// AffiliationManager.GetRelation 应该接收 CombatantEntity 类型。
if (AffiliationManager.Instance.GetRelation(sourceCombatant, currentCombatant) == Relation.Hostile)
{
return true; // 找到第一个敌对的 CombatantEntity 即返回 true提高效率。
}
}
}
return false; // 遍历完所有实体都未找到敌对实体
return false; // 遍历完所有实体都未找到敌对的 CombatantEntity
}
/// <summary>
@ -714,6 +763,22 @@ namespace Managers
return false;
}
// 新增校验:确保源实体自身是一个 CombatantEntity。
var sourceCombatant = sourceEntityPrefab.entity as CombatantEntity;
if (sourceCombatant == null)
{
Debug.LogWarning(
$"实体管理器ExistsHostileInSightRange 方法中,源实体 '{sourceEntityPrefab.name}' 无法转换为 CombatantEntity 类型。无法有效判断是否存在敌对的活跃实体。");
return false;
}
if (sourceCombatant.IsDead)
{
// 源 CombatantEntity 已经失效,它无法判断敌对实体。
// 此时它本身可能也无法移动或感知所以直接返回false。
return false;
}
if (sightRange <= 0)
{
Debug.LogWarning($"实体管理器ExistsHostileInSightRange 方法中,视野范围必须为正值。接收到的值为: {sightRange}。");
@ -737,27 +802,42 @@ namespace Managers
// 预计算平方距离:避免在循环内部重复计算平方根,提高性能。
var sightRangeSqr = sightRange * sightRange;
var sourcePos = sourceEntityPrefab.transform.position;
var sourcePos = sourceCombatant.transform.position; // 修改点:使用 sourceCombatant 的位置
// 遍历所有实体:遍历维度内的所有派系,再遍历每个派系下的所有实体。
foreach (var factionEntities in factionDict.Values)
{
foreach (var currentEntityPrefab in factionEntities)
{
// 实体有效性及排除源实体自身:
// 1. 排除无效或已死亡的实体。
// 1. 排除无效的实体预制体或内部实体。
// 2. 排除源实体自身。
if (currentEntityPrefab == null || currentEntityPrefab.entity == null ||
currentEntityPrefab.entity.IsDead || currentEntityPrefab == sourceEntityPrefab)
currentEntityPrefab == sourceEntityPrefab) // 源实体自身已被转换为 sourceCombatant 并检查,这里只检查 prefab 引用是否相同
{
continue;
}
// 关系判断:判断当前实体与源实体是否为“敌对”关系
if (affiliationManager.GetRelation(sourceEntityPrefab.entity, currentEntityPrefab.entity) ==
Relation.Hostile)
// 【核心改动】新增类型检查:只有能转换为 CombatantEntity 的实体才会被进一步判断
var currentCombatant = currentEntityPrefab.entity as CombatantEntity;
if (currentCombatant == null)
{
continue; // 如果不是 CombatantEntity则跳过此实体。
}
// 检查目标 CombatantEntity 是否已失效(死亡或摧毁)。
if (currentCombatant.IsDead)
{
continue; // 目标 CombatantEntity 已经失效,不是活跃的敌对实体。
}
// 关系判断:判断当前 CombatantEntity 与源 CombatantEntity 是否为“敌对”关系。
if (affiliationManager.GetRelation(sourceCombatant, currentCombatant) ==
Relation.Hostile) // 修改点:使用 CombatantEntity 类型参数
{
// 距离判断:如果关系敌对,进一步判断其是否在视野范围内。
var distanceSqr = Vector3.SqrMagnitude(currentEntityPrefab.transform.position - sourcePos);
var distanceSqr =
Vector3.SqrMagnitude(currentCombatant.transform.position -
sourcePos); // currentCombatant.transform
if (distanceSqr <= sightRangeSqr)
{
return true; // 找到第一个视野范围内的敌对实体即返回 true。