(client)feat:视野范围检测,

This commit is contained in:
m0_75251201
2025-08-25 18:24:12 +08:00
parent 797cf69f75
commit d8a3daaca8
28 changed files with 1340 additions and 519 deletions

View File

@ -6,105 +6,165 @@ using UnityEngine;
namespace Managers
{
/// <summary>
/// 阵营管理器,负责管理游戏中的所有阵营定义及其相互关系。
/// 继承自 <see cref="Utils.Singleton{T}"/> ,确保全局只有一个实例。
/// </summary>
public class AffiliationManager:Utils.Singleton<AffiliationManager>
{
//定义名,阵营定义
/// <summary>
/// 存储所有已加载的阵营定义,键为阵营的唯一名称,值为对应的 <see cref="AffiliationDef"/> 对象。
/// </summary>
private readonly Dictionary<string, AffiliationDef> _affiliations = new();
/// <summary>
/// 初始化阵营管理器,从 <see cref="DefineManager"/> 加载所有 <see cref="AffiliationDef"/>。
/// 在首次需要阵营数据时调用。
/// </summary>
public void Init()
{
// 如果管理器已经初始化,则直接返回,避免重复加载。
if (_affiliations.Count > 0)
{
return;
}
var affiliationList = Managers.DefineManager.Instance.QueryDefinesByType<AffiliationDef>();
if (affiliationList == null ||affiliationList.Length==0)
if (affiliationList == null || affiliationList.Length == 0)
{
// 记录警告,说明未能加载任何阵营定义。
Debug.LogWarning("未找到任何 AffiliationDef 或阵营列表为空。");
return;
}
foreach (var affiliation in affiliationList)
{
_affiliations.Add(affiliation.defName, affiliation);
// 尝试将阵营定义添加到字典中。如果名称已存在,则记录错误。
if (!_affiliations.TryAdd(affiliation.defName, affiliation))
{
Debug.LogError($"添加阵营 '{affiliation.defName}' 失败。已存在同名阵营。");
}
}
// 验证并修复加载后的阵营关系,以确保数据一致性。
ValidateAndFixRelationships();
}
/// <summary>
/// 清除所有已加载的阵营定义。
/// 在游戏会话结束或需要重新加载所有定义时调用。
/// </summary>
public void Clear()
{
_affiliations.Clear();
}
/// <summary>
/// 根据阵营定义名称获取其默认名称。
/// </summary>
/// <param name="defName">阵营的定义名称。</param>
/// <returns>阵营的默认名称。</returns>
public string GetAffiliationName(string defName)
{
return _affiliations[defName].defName;
}
/// <summary>
/// 获取两个阵营间的关系。
/// </summary>
/// <param name="affiliation1">第一个阵营的 <see cref="AffiliationDef"/> 对象。</param>
/// <param name="affiliation2">第二个阵营的 <see cref="AffiliationDef"/> 对象。</param>
/// <returns>两个阵营之间的 <see cref="Relation"/>。</returns>
public Relation GetRelation(AffiliationDef affiliation1, AffiliationDef affiliation2)
{
// 如果任一阵营定义为空,则返回中立关系。
if (affiliation1 == null || affiliation2 == null)
{
return Relation.Neutral; // 如果任一阵营不存在,返回中立关系
return Relation.Neutral;
}
return GetRelation(affiliation1.defName, affiliation2.defName);
}
/// <summary>
/// 获取两个阵营名称之间的关系。
/// </summary>
/// <param name="factionName1">第一个阵营的名称。</param>
/// <param name="factionName2">第二个阵营的名称。</param>
/// <returns>两个阵营之间的 <see cref="Relation"/>。</returns>
public Relation GetRelation(string factionName1, string factionName2)
{
// 如果查询的是同一个派系,默认友好关系
// 如果查询的是同一个阵营,则默认友好关系
if (factionName1 == factionName2)
{
return Relation.Friendly;
}
// 尝试获取两个派系的定义
// 尝试获取两个阵营的定义
if (!_affiliations.TryGetValue(factionName1, out var faction1) ||
!_affiliations.TryGetValue(factionName2, out _))
{
// 如果第一个阵营存在,但第二个不存在,返回第一个阵营的默认关系;
// 否则(两个都不存在或第一个不存在),返回中立。
if (faction1 != null) return faction1.defaultRelation;
// 注意:由于上面已经有一个 TryGetValue 判断,
// 此时 faction1 为 null 表示 factionName1 也不存在,所以应返回中立。
return Relation.Neutral;
}
// 检查faction1是否明确将faction2列为敌对
// 检查 faction1 是否将 faction2 明确列为敌对
if (faction1.hostileFactions != null && faction1.hostileFactions.Contains(factionName2))
{
return Relation.Hostile;
}
// 检查faction1是否明确将faction2列为友好
// 检查 faction1 是否将 faction2 明确列为友好
if (faction1.friendlyFactions != null && faction1.friendlyFactions.Contains(factionName2))
{
return Relation.Friendly;
}
// 检查faction1是否明确将faction2列为中立
// 检查 faction1 是否将 faction2 明确列为中立
if (faction1.neutralFactions != null && faction1.neutralFactions.Contains(factionName2))
{
return Relation.Neutral;
}
// 如果faction1没有明确设置与faction2的关系则使用faction1的默认关系
// 如果 faction1 没有明确设置与 faction2 的关系,则使用 faction1 的默认关系
return faction1.defaultRelation;
}
/// <summary>
/// 设置两个阵营之间的关系
/// 设置两个阵营之间的关系
/// </summary>
/// <param name="factionName1">第一个阵营名称</param>
/// <param name="factionName2">第二个阵营名称</param>
/// <param name="relation">要设置的关系</param>
/// <param name="factionName1">第一个阵营名称</param>
/// <param name="factionName2">第二个阵营名称</param>
/// <param name="relation">要设置的 <see cref="Relation"/>。</param>
/// <exception cref="ArgumentException">当尝试设置同一个阵营的关系或其中一个阵营不存在时抛出。</exception>
/// <exception cref="ArgumentOutOfRangeException">当传入的关系类型无效时抛出。</exception>
public void SetRelation(string factionName1, string factionName2, Relation relation)
{
// 不能设置自己与自己的关系
// 不能设置自己与自己的关系
if (factionName1 == factionName2)
{
throw new ArgumentException("Cannot set relation between the same faction");
throw new ArgumentException("不能设置同一个阵营之间的关系");
}
// 确保两个阵营都存在
// 确保两个阵营都存在
if (!_affiliations.TryGetValue(factionName1, out var faction1) ||
!_affiliations.TryGetValue(factionName2, out _))
{
throw new ArgumentException("One or both factions do not exist");
throw new ArgumentException("一个或两个阵营不存在");
}
// 确保关系列表已初始化
// 确保关系列表已初始化,避免空引用异常。
faction1.hostileFactions ??= new List<string>();
faction1.friendlyFactions ??= new List<string>();
faction1.neutralFactions ??= new List<string>();
// 先移除所有现有关系
// 先移除 factionName2 在 faction1 所有关系列表中的现有关系
faction1.hostileFactions.Remove(factionName2);
faction1.friendlyFactions.Remove(factionName2);
faction1.neutralFactions.Remove(factionName2);
// 添加新关系
// 根据传入的关系类型,将 factionName2 添加到对应列表中。
switch (relation)
{
case Relation.Hostile:
@ -117,43 +177,45 @@ namespace Managers
faction1.neutralFactions.Add(factionName2);
break;
default:
// 如果传入的关系类型无效,抛出异常。
throw new ArgumentOutOfRangeException(nameof(relation), relation, null);
}
}
/// <summary>
/// 检查并修复派系关系,确保没有冲突(按友好 > 敌对 > 中立 的优先级)
/// 检查并修复所有阵营之间的关系,确保没有冲突
/// 修复遵循优先级规则:友好关系优先于敌对关系,敌对关系优先于中立关系。
/// </summary>
private void ValidateAndFixRelationships()
{
foreach (var faction in _affiliations.Values)
{
// 确保所有关系列表已初始化
// 确保所有关系列表已初始化,避免空引用异常。
faction.hostileFactions ??= new List<string>();
faction.friendlyFactions ??= new List<string>();
faction.neutralFactions ??= new List<string>();
// 检查所有敌对派系
// 遍历并检查所有敌对阵营。由于可能修改列表,使用 ToList() 创建副本进行遍历。
foreach (var hostileFaction in faction.hostileFactions.ToList())
{
// 如果敌对派系同时存在于友好列表中,移除敌对关系(友好优先)
// 如果敌对阵营同时存在于友好列表中,移除敌对关系(友好关系具有更高优先级)。
if (faction.friendlyFactions.Contains(hostileFaction))
{
faction.hostileFactions.Remove(hostileFaction);
continue;
continue; // 继续检查下一个敌对阵营。
}
// 如果敌对派系同时存在于中立列表中,移除中立关系(敌对优先)
// 如果敌对阵营同时存在于中立列表中,移除中立关系(敌对关系具有更高优先级)。
if (faction.neutralFactions.Contains(hostileFaction))
{
faction.neutralFactions.Remove(hostileFaction);
}
}
// 检查所有中立派系
// 遍历并检查所有中立阵营。由于可能修改列表,使用 ToList() 创建副本进行遍历。
foreach (var neutralFaction in faction.neutralFactions.ToList())
{
// 如果中立派系同时存在于友好列表中,移除中立关系(友好优先)
// 如果中立阵营同时存在于友好列表中,移除中立关系(友好关系具有更高优先级)。
if (faction.friendlyFactions.Contains(neutralFaction))
{
faction.neutralFactions.Remove(neutralFaction);
@ -162,4 +224,4 @@ namespace Managers
}
}
}
}
}

View File

@ -218,11 +218,11 @@ namespace Managers
/// <returns>如果找到,返回转换为目标类型的 Define 对象;否则返回 null。</returns>
public T FindDefine<T>(string defineName) where T : Define
{
foreach (var typeDict in defines.Values)
if (defines.TryGetValue(typeof(T).Name, out var typeDict))
{
if (typeDict.TryGetValue(defineName, out var define) && define is T result)
if (typeDict.TryGetValue(defineName, out var define))
{
return result;
return (T)define;
}
}
return null;

View File

@ -3,102 +3,271 @@ using System.Collections.Generic;
using System.Linq;
using Base;
using Entity;
using Map;
using Prefab;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.Serialization;
namespace Managers
{
public class EntityManage : Utils.MonoSingleton<EntityManage>, ITick
{
public Dictionary<string, LinkedList<EntityPrefab>> factionEntities = new();
// --- 新增:维度感知的实体存储结构 ---
// 外层字典DimensionId -> 内层字典
// 内层字典FactionKey -> LinkedList<EntityPrefab>
private Dictionary<string, Dictionary<string, LinkedList<EntityPrefab>>> _dimensionFactionEntities = new();
// --- 新增:当前场景中活跃的维度实例 ---
private Dictionary<string, Dimension> _activeDimensions = new();
// --- 新增:维度感知的层级缓存 ---
// DimensionId -> LayerName -> Transform
private Dictionary<string, Dictionary<string, Transform>> _dimensionLayerCache = new();
// --- 待添加实体列表,现在包含 DimensionId ---
private List<Tuple<string, string, EntityPrefab>>
_pendingAdditions = new(); // Item1: DimensionId, Item2: FactionKey, Item3: EntityPrefab
// --- 现有预制体 (保持不变) ---
public EntityPrefab characterPrefab;
public EntityPrefab buildingPrefab;
public EntityPrefab bulletPrefab;
public EntityPrefab defaultEntityPrefab;
private Dictionary<string, Transform> layerCache = new Dictionary<string, Transform>();
private List<Tuple<string, EntityPrefab>> pendingAdditions = new();
public LinkedList<EntityPrefab> FindEntitiesByFaction(string factionKey)
public void RegisterDimension(Dimension dimension)
{
if (factionEntities.TryGetValue(factionKey, out var entities))
if (dimension == null || string.IsNullOrEmpty(dimension.DimensionId))
{
return entities; // 如果找到,返回对应的实体列表
Debug.LogError("Attempted to register a null or invalid Dimension.");
return;
}
return new(); // 如果未找到,返回一个空列表
if (_activeDimensions.TryGetValue(dimension.DimensionId, out var existingDimension))
{
if (existingDimension == dimension)
{
// 【逻辑修改】如果是同一个实例重复注册,只做信息提示,不警告
Debug.Log($"Dimension with ID '{dimension.DimensionId}' already registered with the same instance. Skipping re-registration.");
return; // 已经注册且是同一个实例,直接返回
}
else
{
// 【逻辑修改】如果是不同实例但ID相同这是严重错误
Debug.LogError(
$"CRITICAL ERROR: Dimension with ID '{dimension.DimensionId}' is already registered with a DIFFERENT instance ({existingDimension.name} vs {dimension.name}). This indicates a duplicate DimensionId in the scene. The new instance will overwrite the old one, which may lead to unexpected behavior. Please ensure all Dimension objects have unique IDs.");
// 允许覆盖,但以错误日志形式提示,强制开发者修复场景配置。
}
}
_activeDimensions[dimension.DimensionId] = dimension;
Debug.Log($"Dimension '{dimension.DimensionId}' registered with EntityManage.");
// 为新注册的维度初始化其数据结构
// 这些检查是必要的,以防止在重复注册时清空现有数据。
if (!_dimensionFactionEntities.ContainsKey(dimension.DimensionId))
{
_dimensionFactionEntities[dimension.DimensionId] = new Dictionary<string, LinkedList<EntityPrefab>>();
}
if (!_dimensionLayerCache.ContainsKey(dimension.DimensionId))
{
_dimensionLayerCache[dimension.DimensionId] = new Dictionary<string, Transform>();
}
}
public void Tick()
{
foreach (var faction in factionEntities)
{
var entitiesToRemove = new List<EntityPrefab>();
foreach (var entityPrefab in faction.Value)
/// <summary>
/// 从实体管理器注销一个维度。
/// </summary>
/// <param name="dimension">要注销的维度实例。</param>
public void UnregisterDimension(Dimension dimension)
{
if (dimension == null || string.IsNullOrEmpty(dimension.DimensionId))
{
Debug.LogError("Attempted to unregister a null or invalid Dimension.");
return;
}
if (_activeDimensions.Remove(dimension.DimensionId))
{
// 当维度被注销时,清理其所有相关的实体和层级缓存
_dimensionFactionEntities.Remove(dimension.DimensionId);
_dimensionLayerCache.Remove(dimension.DimensionId);
// 【逻辑修改】立即清理_pendingAdditions中属于该维度的实体
// 创建一个新列表来存储不属于该维度的实体
var remainingPendingAdditions = new List<Tuple<string, string, EntityPrefab>>();
foreach (var pending in _pendingAdditions)
{
if (entityPrefab.entity.IsDead)
if (pending.Item1 == dimension.DimensionId)
{
entitiesToRemove.Add(entityPrefab);
// 销毁实体GameObject
if (pending.Item3 != null && pending.Item3.gameObject != null) // 增加gameObject的null检查
{
Destroy(pending.Item3.gameObject);
}
}
else
{
ITick itike = entityPrefab.entity;
itike.Tick();
remainingPendingAdditions.Add(pending);
}
}
_pendingAdditions = remainingPendingAdditions; // 更新_pendingAdditions列表
}
}
// 删除所有标记为死亡的实体
foreach (var entityToRemove in entitiesToRemove)
/// <summary>
/// 根据ID获取一个活跃的维度实例。
/// </summary>
/// <param name="dimensionId">维度的唯一标识符。</param>
/// <returns>对应的 Dimension 实例,如果不存在则为 null。</returns>
public Dimension GetDimension(string dimensionId)
{
_activeDimensions.TryGetValue(dimensionId, out var dimension);
return dimension;
}
// --- 查找实体 (现在维度感知) ---
/// <summary>
/// 在指定维度中,根据派系键查找所有实体。
/// </summary>
/// <param name="dimensionId">维度的唯一标识符。</param>
/// <param name="factionKey">派系键。</param>
/// <returns>指定派系下的实体列表,如果未找到则返回空列表。</returns>
public LinkedList<EntityPrefab> FindEntitiesByFaction(string dimensionId, string factionKey)
{
if (_dimensionFactionEntities.TryGetValue(dimensionId, out var factionDict))
{
if (factionDict.TryGetValue(factionKey, out var entities))
{
faction.Value.Remove(entityToRemove);
Destroy(entityToRemove.gameObject);
return entities;
}
}
if (pendingAdditions.Any())
{
foreach (var entity in pendingAdditions)
{
if (!factionEntities.ContainsKey(entity.Item1))
{
factionEntities[entity.Item1] = new LinkedList<EntityPrefab>();
}
return new LinkedList<EntityPrefab>(); // 如果未找到,返回一个空列表
}
factionEntities[entity.Item1].AddLast(entity.Item2);
// --- Tick 方法 (现在维度感知) ---
public void Tick()
{
// 遍历每个活跃的维度
foreach (var dimensionEntry in _dimensionFactionEntities.ToList()) // ToList() 避免在迭代时修改字典
{
var dimensionId = dimensionEntry.Key;
var factionDict = dimensionEntry.Value;
// 检查维度对象本身是否仍然活跃在场景中
// 注意:这里检查的是 _activeDimensions确保 Dimension 对象实例仍然存在且被管理器追踪。
if (!_activeDimensions.ContainsKey(dimensionId))
{
Debug.LogWarning(
$"Skipping Tick for dimension '{dimensionId}' as its Dimension object is no longer active. Clearing its entities.");
_dimensionFactionEntities.Remove(dimensionId); // 移除已失效维度的实体数据
_dimensionLayerCache.Remove(dimensionId); // 移除已失效维度的层级缓存
continue;
}
pendingAdditions.Clear();
foreach (var faction in factionDict)
{
var entitiesToRemove = new List<EntityPrefab>();
var currentEntities = faction.Value.ToList(); // 创建副本以避免在迭代时修改列表
foreach (var entityPrefab in currentEntities)
{
// 检查实体预制体或其内部实体是否已销毁或死亡
if (entityPrefab == null || entityPrefab.entity == null || entityPrefab.entity.IsDead)
{
entitiesToRemove.Add(entityPrefab);
}
else
{
ITick itike = entityPrefab.entity;
itike.Tick();
}
}
// 删除所有标记为死亡的实体
foreach (var entityToRemove in entitiesToRemove)
{
faction.Value.Remove(entityToRemove);
if (entityToRemove != null) // 确保它没有被外部销毁
{
Destroy(entityToRemove.gameObject);
}
}
}
}
// 处理待添加实体 (现在维度感知)
if (_pendingAdditions.Any())
{
foreach (var pending in _pendingAdditions)
{
var dimensionId = pending.Item1;
var factionKey = pending.Item2;
var entityPrefab = pending.Item3;
// 再次检查维度是否活跃,防止在添加前维度被注销
if (!_dimensionFactionEntities.ContainsKey(dimensionId))
{
Debug.LogError(
$"Attempted to add entity '{entityPrefab.name}' to unregistered or inactive dimension '{dimensionId}'. Entity will be destroyed.");
if (entityPrefab != null) Destroy(entityPrefab.gameObject);
continue;
}
var factionDict = _dimensionFactionEntities[dimensionId];
if (!factionDict.ContainsKey(factionKey))
{
factionDict[factionKey] = new LinkedList<EntityPrefab>();
}
factionDict[factionKey].AddLast(entityPrefab);
}
_pendingAdditions.Clear();
}
}
/// <summary>
/// 根据给定的Def生成实体对象内部通用方法
/// </summary>
/// <param name="dimensionId">实体所属的维度ID。</param>
/// <param name="prefab">要实例化的预制体</param>
/// <param name="parent">生成的父级Transform</param>
/// <param name="pos">生成位置</param>
/// <param name="def">实体定义对象</param>
/// <param name="extraInit">额外的初始化操作(如子弹方向设置)</param>
/// <returns>成功时返回EntityPrefab组件失败时返回null</returns>
private EntityPrefab GenerateEntityInternal(
string dimensionId, // 新增参数维度ID
GameObject prefab,
Transform parent,
Vector3 pos,
Data.EntityDef def, // 所有Def类型需继承自BaseDef
Data.EntityDef def,
Action<EntityPrefab> extraInit = null)
{
// 验证维度是否活跃
if (!_activeDimensions.TryGetValue(dimensionId, out var dimension))
{
Debug.LogError($"Cannot generate entity: Dimension '{dimensionId}' is not active or registered.");
return null;
}
// 获取或创建实体所属的层级Transform并确保其在维度根下
var parentLayer = EnsureLayerExists(dimensionId, "DefaultEntityLevel"); // 使用一个默认层级名称
if (parentLayer == null)
{
Debug.LogError($"Failed to get or create parent layer for entity in dimension '{dimensionId}'.");
return null;
}
GameObject instantiatedEntity = null;
try
{
// 实例化实体
instantiatedEntity = Instantiate(prefab, pos, Quaternion.identity, parent);
// 实例化实体并将其父级设置为维度下的层级Transform
instantiatedEntity = Instantiate(prefab, pos, Quaternion.identity, parentLayer);
// 获取并验证EntityPrefab组件
var entityComponent = instantiatedEntity.GetComponent<EntityPrefab>();
if (!entityComponent)
{
@ -106,204 +275,231 @@ namespace Managers
$"EntityPrefab component missing on: {instantiatedEntity.name}");
}
// 初始化核心数据
entityComponent.Init(def);
// 执行类型特有的额外初始化
extraInit?.Invoke(entityComponent);
// 管理派系列表
var factionKey = def.attributes.defName ?? "default";
pendingAdditions.Add(Tuple.Create(factionKey, entityComponent));
var factionKey = def.attributes.defName ?? "default"; // 假设 attributes.defName 是派系键
_pendingAdditions.Add(Tuple.Create(dimensionId, factionKey, entityComponent)); // 添加维度ID
return entityComponent;
}
catch (System.Exception ex)
{
// 清理失败实例
if (instantiatedEntity) Destroy(instantiatedEntity);
Debug.LogError($"Entity generation failed: {ex.Message}\n{ex.StackTrace}");
Debug.LogError($"Entity generation failed in dimension '{dimensionId}': {ex.Message}\n{ex.StackTrace}");
return null;
}
}
/// <summary>
/// 动态创建层(如果层不存在)
/// 动态创建层(如果层不存在),现在是维度感知的。
/// 每个维度有自己的层级结构,根在 Dimension.DimensionRoot 下。
/// </summary>
private Transform EnsureLayerExists(string layerName)
/// <param name="dimensionId">维度的唯一标识符。</param>
/// <param name="layerName">要确保存在的层级名称。</param>
/// <returns>层级Transform如果维度不存在或其根Transform为空则返回null。</returns>
private Transform EnsureLayerExists(string dimensionId, string layerName)
{
// 先从缓存中查找
if (layerCache.TryGetValue(layerName, out var layerTransform))
// 尝试从维度层级缓存中获取
if (!_dimensionLayerCache.TryGetValue(dimensionId, out var layerCacheForDimension))
{
Debug.LogError(
$"Dimension '{dimensionId}' not found in layer cache. This should not happen if dimension is registered.");
return null;
}
if (layerCacheForDimension.TryGetValue(layerName, out var layerTransform))
{
return layerTransform;
}
// 如果缓存中没有,尝试通过 transform.Find 查找
layerTransform = transform.Find(layerName);
// 如果缓存中没有,尝试在维度根下查找
var dimension = GetDimension(dimensionId);
if (dimension == null || dimension.DimensionRoot == null)
{
Debug.LogError(
$"Dimension '{dimensionId}' or its root transform is null. Cannot create layer '{layerName}'.");
return null;
}
layerTransform = dimension.DimensionRoot.Find(layerName);
if (!layerTransform)
{
// 如果层不存在,动态创建
// 如果层不存在,动态创建并将其父级设置为维度的根Transform
var layerObject = new GameObject(layerName);
layerTransform = layerObject.transform;
layerTransform.SetParent(dimension.DimensionRoot);
}
// 将新创建的层加入缓存
layerCache[layerName] = layerTransform;
layerCacheForDimension[layerName] = layerTransform;
return layerTransform;
}
// --- 公共生成方法 (现在维度感知) ---
/// <summary>
/// 根据PawnDef生成普通实体
/// 在指定维度中,根据PawnDef生成普通实体
/// </summary>
public void GenerateEntity(Data.EntityDef entityDef, Vector3 pos)
public void GenerateEntity(string dimensionId, Data.EntityDef entityDef, Vector3 pos)
{
// 验证关键参数
if (!characterPrefab)
{
Debug.LogError("entityPrefab is null! Assign a valid prefab.");
GenerateDefaultEntity(pos);
Debug.LogError("characterPrefab is null! Assign a valid prefab.");
GenerateDefaultEntity(dimensionId, pos);
return;
}
if (entityDef == null)
{
Debug.LogError("EntityDef is null! Cannot generate entity.");
GenerateDefaultEntity(pos);
GenerateDefaultEntity(dimensionId, pos);
return;
}
// 确保层存在
var entityLevelTransform = EnsureLayerExists("EntityLevel");
// 调用通用生成逻辑
var result = GenerateEntityInternal(
dimensionId,
characterPrefab.gameObject,
entityLevelTransform,
pos,
entityDef
);
if (!result) GenerateDefaultEntity(pos);
if (!result) GenerateDefaultEntity(dimensionId, pos);
}
/// <summary>
/// 生成建筑实体位置使用Vector3Int
/// 在指定维度中,生成建筑实体位置使用Vector3Int
/// </summary>
public void GenerateBuildingEntity(Data.BuildingDef buildingDef, Vector3Int pos)
public void GenerateBuildingEntity(string dimensionId, Data.BuildingDef buildingDef, Vector3Int pos)
{
// 修正:检查正确的预制体 (buildingPrefab)
if (!buildingPrefab)
{
Debug.LogError("buildingPrefab is null! Assign a valid prefab.");
GenerateDefaultEntity(pos);
GenerateDefaultEntity(dimensionId, pos);
return;
}
if (buildingDef == null)
{
Debug.LogError("BuildingDef is null! Cannot generate building.");
GenerateDefaultEntity(pos);
GenerateDefaultEntity(dimensionId, pos);
return;
}
var worldPos = new Vector3(pos.x, pos.y, pos.z);
// 确保层存在
var buildingLevelTransform = EnsureLayerExists("BuildingLevel");
var result = GenerateEntityInternal(
dimensionId,
buildingPrefab.gameObject,
buildingLevelTransform,
worldPos,
buildingDef
);
if (!result) GenerateDefaultEntity(worldPos);
if (!result) GenerateDefaultEntity(dimensionId, worldPos);
}
/// <summary>
/// 生成子弹实体(含方向设置)
/// 在指定维度中,生成子弹实体(含方向设置)
/// </summary>
public void GenerateBulletEntity(Data.BulletDef bulletDef, Vector3 pos, Vector3 dir,
public void GenerateBulletEntity(string dimensionId, Data.BulletDef bulletDef, Vector3 pos, Vector3 dir,
Entity.Entity source = null)
{
// 修正:检查正确的预制体 (bulletPrefab)
if (!bulletPrefab)
{
Debug.LogError("bulletPrefab is null! Assign a valid prefab.");
GenerateDefaultEntity(pos);
GenerateDefaultEntity(dimensionId, pos);
return;
}
if (bulletDef == null)
{
Debug.LogError("BulletDef is null! Cannot generate bullet.");
GenerateDefaultEntity(pos);
GenerateDefaultEntity(dimensionId, pos);
return;
}
// 确保层存在
var bulletLevelTransform = EnsureLayerExists("BulletLevel");
var result = GenerateEntityInternal(
dimensionId,
bulletPrefab.gameObject,
bulletLevelTransform,
pos,
bulletDef,
// 子弹特有的方向设置
entityComponent => entityComponent.entity.SetTarget(pos + dir)
);
if (result.entity is Bullet bullet)
// 确保 result 不为 null 且 entity 是 Bullet 类型
if (result != null && result.entity is Bullet bullet)
{
bullet.bulletSource = source;
if (source) bullet.affiliation = source.affiliation;
if (source != null) bullet.affiliation = source.affiliation; // 确保 source 不为 null
}
if (!result) GenerateDefaultEntity(pos);
if (!result) GenerateDefaultEntity(dimensionId, pos);
}
/// <summary>
/// 生成默认实体(错误回退)
/// 在指定维度中,生成默认实体(错误回退)
/// </summary>
public void GenerateDefaultEntity(Vector3 pos)
public void GenerateDefaultEntity(string dimensionId, Vector3 pos)
{
// 确保层存在
var entityLevelTransform = EnsureLayerExists("EntityLevel");
if (!_activeDimensions.ContainsKey(dimensionId))
{
Debug.LogError(
$"Cannot generate default entity: Dimension '{dimensionId}' is not active or registered.");
return;
}
var entity = Instantiate(defaultEntityPrefab, pos, Quaternion.identity, entityLevelTransform);
var parentLayer = EnsureLayerExists(dimensionId, "DefaultEntityLevel");
if (parentLayer == null)
{
Debug.LogError($"Failed to get parent transform for default entity in dimension '{dimensionId}'.");
return;
}
var entity = Instantiate(defaultEntityPrefab, pos, Quaternion.identity, parentLayer);
var entityComponent = entity.GetComponent<EntityPrefab>();
const string factionKey = "default";
pendingAdditions.Add(Tuple.Create(factionKey, entityComponent));
_pendingAdditions.Add(Tuple.Create(dimensionId, factionKey, entityComponent));
entityComponent.DefaultInit();
}
// --- 单例生命周期与场景切换处理 ---
protected override void OnStart()
{
SceneManager.sceneLoaded += OnSceneLoaded;
}
private void OnDestroy()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
}
protected override void OnStart()
{
SceneManager.sceneLoaded += OnSceneLoaded;
}
/// <summary>
/// 场景加载完成时的回调。
/// 清理旧场景的实体数据,并重新扫描新场景中的维度。
/// </summary>
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
factionEntities.Clear();
layerCache.Clear();
pendingAdditions.Clear();
_dimensionFactionEntities.Clear(); // 清理所有维度下的实体数据
_dimensionLayerCache.Clear(); // 清理所有维度下的层级缓存
_pendingAdditions.Clear(); // 清理待添加实体列表
_activeDimensions.Clear(); // 清理活跃维度列表,因为旧场景的维度对象已被销毁
}
private void Start()
{
var pre = Resources.Load<GameObject>("Default/DefaultEntity");
defaultEntityPrefab = pre.GetComponent<EntityPrefab>();
layerCache.Clear();
if (defaultEntityPrefab == null)
{
var pre = Resources.Load<GameObject>("Default/DefaultEntity");
if (pre != null)
{
defaultEntityPrefab = pre.GetComponent<EntityPrefab>();
}
else
{
Debug.LogError(
"Failed to load DefaultEntity prefab from Resources/Default/DefaultEntity. Please ensure it exists at 'Assets/Resources/Default/DefaultEntity.prefab'.");
}
}
}
}
}

View File

@ -2,46 +2,122 @@ using System.Collections.Generic;
using System.Linq;
using Data;
using Item;
using UnityEngine;
namespace Managers
{
public class ItemResourceManager:Utils.Singleton<ItemResourceManager>
public class ItemResourceManager : Utils.Singleton<ItemResourceManager>
{
//定义名,物品
public Dictionary<string,Item.ItemResource> items;
private readonly Dictionary<string, Item.ItemResource> _items = new();
private readonly Dictionary<string, List<Item.ItemResource>> _itemsByName = new(); // 保持按显示名称查找的字典
public void Init()
{
var itemDefs = Managers.DefineManager.Instance.QueryDefinesByType<ItemDef>();
if(itemDefs==null||itemDefs.Length==0)
var baseItemDefs = Managers.DefineManager.Instance.QueryDefinesByType<ItemDef>();
var weaponDefs = Managers.DefineManager.Instance.QueryDefinesByType<WeaponDef>();
var allDefs = new List<ItemDef>();
if (baseItemDefs != null) allDefs.AddRange(baseItemDefs);
if (weaponDefs != null) allDefs.AddRange(weaponDefs);
if (allDefs.Count == 0)
{
Debug.LogWarning("ItemResourceManager: No ItemDef or WeaponDef found to initialize.");
return;
foreach (var itemDef in itemDefs)
{
var item=new Item.ItemResource();
item.name = itemDef.label;
item.description = itemDef.description;
item.icon = Managers.PackagesImageManager.Instance.GetSprite(itemDef.texture);
}
foreach (var def in allDefs)
{
if (_items.ContainsKey(def.defName))
{
Debug.LogError(
$"ItemResourceManager: Duplicate itemDef.defName found: {def.defName}. Skipping this item.");
continue;
}
var itemIcon = Managers.PackagesImageManager.Instance.GetSprite(def.texture);
if (!itemIcon)
{
Debug.LogWarning(
$"ItemResourceManager: Failed to load sprite for texture '{def.texture}' for item '{def.defName}'. Icon will be null.");
}
var itemName = string.IsNullOrEmpty(def.label) ? def.defName : def.label;
if (string.IsNullOrEmpty(def.label))
{
Debug.LogWarning(
$"ItemResourceManager: ItemDef '{def.defName}' has an empty label. Using defName as item name.");
}
var itemDescription = def.description ?? string.Empty;
Item.ItemResource itemResource;
if (def is WeaponDef currentWeaponDef)
{
itemResource = new Item.WeaponResource(
def.defName, // 传递 defName
itemName,
itemDescription,
itemIcon,
currentWeaponDef.rarity,
currentWeaponDef.maxStack,
currentWeaponDef.ssEquippable,
currentWeaponDef.attributes
);
}
else
{
itemResource = new Item.ItemResource(
def.defName, // 传递 defName
itemName,
itemDescription,
itemIcon,
def.rarity,
def.maxStack,
def.ssEquippable
);
}
_items.Add(def.defName, itemResource);
// 将物品添加到按显示名称查找的字典 (这里仍然使用 itemResource.Name因为字典的目的是按显示名称查找)
if (!_itemsByName.ContainsKey(itemResource.Name))
{
_itemsByName.Add(itemResource.Name, new List<Item.ItemResource>());
}
_itemsByName[itemResource.Name].Add(itemResource);
}
Debug.Log($"ItemResourceManager: Initialized {_items.Count} items.");
}
public ItemResource GetItem(string defName)
public Item.ItemResource GetItem(string defName)
{
return items.GetValueOrDefault(defName,null);
return _items.GetValueOrDefault(defName, null);
}
// <summary>
/// 按物品名称查找物品
/// </summary>
/// <param name="itemName">要查找的物品名称</param>
/// <returns>找到的物品对象,如果未找到则返回 null</returns>
public ItemResource FindItemByName(string itemName)
// FindItemByName 和 FindAllItemsByName 保持不变,因为它们是按显示名称查找
public Item.ItemResource FindItemByName(string itemName)
{
if (string.IsNullOrEmpty(itemName))
{
return null;
}
return items.Values.FirstOrDefault(item => item.name == itemName);
if (string.IsNullOrEmpty(itemName)) return null;
return _itemsByName.GetValueOrDefault(itemName)?.FirstOrDefault();
}
public List<Item.ItemResource> FindAllItemsByName(string itemName)
{
if (string.IsNullOrEmpty(itemName)) return new List<Item.ItemResource>();
return _itemsByName.GetValueOrDefault(itemName, new List<Item.ItemResource>());
}
public void Clear()
{
_items.Clear();
_itemsByName.Clear();
Debug.Log("ItemResourceManager: All item resources cleared.");
}
}
}