mirror of
http://47.107.252.169:3000/Roguelite-Game-Developing-Team/Gen_Hack-and-Slash-Roguelite.git
synced 2025-11-20 04:07:13 +08:00
(client) feat:添加基地界面到游玩界面的过程,添加存档管理,技能树变得可用 (#58)
Co-authored-by: m0_75251201 <m0_75251201@noreply.gitcode.com> Reviewed-on: http://47.107.252.169:3000/Roguelite-Game-Developing-Team/Gen_Hack-and-Slash-Roguelite/pulls/58
This commit is contained in:
@@ -157,6 +157,7 @@ namespace EventWorkClass
|
||||
Debug.LogWarning($"实体定义类型名为空或null (实体定义名: '{entry.DefName}')。跳过此定义。");
|
||||
continue;
|
||||
}
|
||||
// 遵循“单例总是有效”的指示,不检查 DefineManager.Instance 是否为 null
|
||||
var entityDef = (EntityDef)DefineManager.Instance.FindDefine(entry.DefTypeName, entry.DefName);
|
||||
if (entityDef == null)
|
||||
{
|
||||
@@ -191,23 +192,31 @@ namespace EventWorkClass
|
||||
return;
|
||||
}
|
||||
|
||||
// 遵循“单例总是有效”的指示,不检查 EntityManager.Instance 是否为 null
|
||||
// 如果 EntityManager.Instance 为 null,则表明单例系统存在问题,
|
||||
// 此时应由单例系统自身处理其初始化错误,而不是每次使用时都进行防御性检查。
|
||||
// 例如,如果 EntityManager.Instance 本身就是 null,下面的 GenerateCharacterEntity 将抛出 NullReferenceException。
|
||||
// 根据“单例总是有效”的指示,我们将此视为单例系统层面的设计或实现缺陷,而非 Event_EntityGenerater 的问题。
|
||||
|
||||
for (int i = 0; i < _config.Count; i++)
|
||||
for (var i = 0; i < _config.Count; i++)
|
||||
{
|
||||
// 随机选择一个实体定义
|
||||
var selectedEntityDef = _validatedEntityDefs[Random.Range(0, _validatedEntityDefs.Count)];
|
||||
|
||||
var position = GetPosition(dimensionID);
|
||||
// 检查 GetPosition 是否返回了有效的非零位置,除非它是 AroundSpecificCoordinates 且中心点就是 Vector3.zero
|
||||
if (position == Vector3.zero && (_config.LocationType != EntitySpawnLocationType.AroundSpecificCoordinates
|
||||
|| _config.CenterCoordinates != Vector3.zero))
|
||||
// 逻辑修改点1:检查 GetPosition 是否返回了有效的非零位置,或者其零点是明确配置的。
|
||||
// 如果 position 为 Vector3.zero 且不是由 AroundSpecificCoordinates 且中心点为 Vector3.zero 引起的,则跳过本次生成。
|
||||
var isZeroDueToError = (position == Vector3.zero && (_config.LocationType != EntitySpawnLocationType.AroundSpecificCoordinates
|
||||
|| _config.CenterCoordinates != Vector3.zero));
|
||||
if (isZeroDueToError)
|
||||
{
|
||||
Debug.LogWarning($"未能为类型 {_config.LocationType} 获取有效的生成位置。实体可能在原点 (0,0,0) 生成。");
|
||||
Debug.LogWarning($"未能为类型 {_config.LocationType} 获取有效的生成位置。跳过本次实体生成。");
|
||||
continue; // 跳过本次循环,不生成实体
|
||||
}
|
||||
|
||||
if (selectedEntityDef is CharacterDef characterDef)
|
||||
{
|
||||
EntityManager.Instance.GenerateEntity(dimensionID, characterDef, position);
|
||||
EntityManager.Instance.GenerateCharacterEntity(dimensionID, characterDef, position);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -233,6 +242,7 @@ namespace EventWorkClass
|
||||
Debug.LogError("获取位置时配置为空。返回 Vector3.zero。");
|
||||
return Vector3.zero;
|
||||
}
|
||||
// 遵循“单例总是有效”的指示,不检查 Program.Instance 是否为 null
|
||||
var dimension = Program.Instance.GetDimension(dimensionID);
|
||||
if (dimension == null)
|
||||
{
|
||||
@@ -240,9 +250,10 @@ namespace EventWorkClass
|
||||
return Vector3.zero;
|
||||
}
|
||||
var mapGenerator = dimension.landform;
|
||||
if (mapGenerator == null)
|
||||
// 逻辑修改点2:更准确的错误信息
|
||||
if (mapGenerator == null)
|
||||
{
|
||||
Debug.LogError($"维度 '{dimensionID}' 的地图生成器为空。无法确定生成位置。");
|
||||
Debug.LogError($"维度 '{dimensionID}' 的地形 (landform) 为空。无法确定生成位置。"); // 错误信息更清晰
|
||||
return Vector3.zero;
|
||||
}
|
||||
switch (_config.LocationType)
|
||||
@@ -294,7 +305,9 @@ namespace EventWorkClass
|
||||
var center = _config.CenterCoordinates;
|
||||
var radius = _config.Radius;
|
||||
var randomOffset = Random.insideUnitCircle * radius;
|
||||
return new Vector3(center.x + randomOffset.x, center.y + randomOffset.y, center.z);
|
||||
var rawPosition = new Vector3(center.x + randomOffset.x, center.y + randomOffset.y, center.z);
|
||||
// 逻辑修改点4:应用位置钳制,确保在地图范围内
|
||||
return GetClampedWorldPosition(rawPosition, dimensionID);
|
||||
}
|
||||
case EntitySpawnLocationType.AroundTargetEntity:
|
||||
{
|
||||
@@ -303,6 +316,7 @@ namespace EventWorkClass
|
||||
Debug.LogWarning($"配置了 'AroundTargetEntity',但 'TargetFactionDefName' 为空或null。无法找到派系实体。将在原点生成。");
|
||||
return Vector3.zero;
|
||||
}
|
||||
// 遵循“单例总是有效”的指示,不检查 EntityManager.Instance 是否为 null
|
||||
var factionEntities = EntityManager.Instance.FindEntitiesByFaction(dimensionID, _config.TargetFactionDefName);
|
||||
if (factionEntities == null || factionEntities.Length == 0)
|
||||
{
|
||||
@@ -311,7 +325,8 @@ namespace EventWorkClass
|
||||
}
|
||||
var randomIndex = Random.Range(0, factionEntities.Length);
|
||||
var targetEntityPrefab = factionEntities[randomIndex];
|
||||
if (targetEntityPrefab == null || targetEntityPrefab.transform == null)
|
||||
// Unity对象隐式空比较
|
||||
if (targetEntityPrefab == null || targetEntityPrefab.transform == null)
|
||||
{
|
||||
Debug.LogWarning($"从派系 '{_config.TargetFactionDefName}' 中随机选择的实体为空或没有Transform组件。将在原点生成。");
|
||||
return Vector3.zero;
|
||||
@@ -320,8 +335,10 @@ namespace EventWorkClass
|
||||
var radius = _config.Radius;
|
||||
var randomOffset = Random.insideUnitCircle * radius;
|
||||
|
||||
var rawPosition = new Vector3(center.x + randomOffset.x, center.y + randomOffset.y, center.z);
|
||||
Debug.Log($"围绕派系 '{_config.TargetFactionDefName}' 的实体 (世界坐标: {center}) 生成。生成的偏移量: {randomOffset}。");
|
||||
return new Vector3(center.x + randomOffset.x, center.y + randomOffset.y, center.z);
|
||||
// 逻辑修改点4:应用位置钳制,确保在地图范围内
|
||||
return GetClampedWorldPosition(rawPosition, dimensionID);
|
||||
}
|
||||
case EntitySpawnLocationType.RandomlyOnMap:
|
||||
{
|
||||
@@ -350,5 +367,60 @@ namespace EventWorkClass
|
||||
return Vector3.zero;
|
||||
}
|
||||
}
|
||||
|
||||
// 逻辑修改点3:新增 GetClampedWorldPosition 辅助方法
|
||||
/// <summary>
|
||||
/// 将给定的世界坐标限制在指定维度的地图可玩区域边界内。
|
||||
/// 假设 mapGenerator.GetWorldCoordinates(gridPos) 返回瓦片中心,且瓦片世界大小为 1x1 单位。
|
||||
/// </summary>
|
||||
/// <param name="worldPosition">待限制的世界坐标。</param>
|
||||
/// <param name="dimensionID">目标维度ID。</param>
|
||||
/// <returns>限制在地图边界内的世界坐标。</returns>
|
||||
private Vector3 GetClampedWorldPosition(Vector3 worldPosition, string dimensionID)
|
||||
{
|
||||
// 遵循“单例总是有效”的指示,不检查 Program.Instance 是否为 null
|
||||
var dimension = Program.Instance.GetDimension(dimensionID);
|
||||
if (dimension == null)
|
||||
{
|
||||
Debug.LogError($"无法获取维度 '{dimensionID}' 来限制位置。返回原始位置。");
|
||||
return worldPosition;
|
||||
}
|
||||
var mapGenerator = dimension.landform;
|
||||
if (mapGenerator == null)
|
||||
{
|
||||
Debug.LogError($"维度 '{dimensionID}' 的地形 (landform) 为空。无法限制位置。返回原始位置。");
|
||||
return worldPosition;
|
||||
}
|
||||
|
||||
var mapGridSize = mapGenerator.GetSize(); // 获取地图的网格尺寸 (宽度, 高度)
|
||||
|
||||
// 假设 GetWorldCoordinates(gridPos) 返回瓦片中心,且世界坐标中的单瓦片尺寸为 1x1。
|
||||
// 所以,瓦片的半个世界尺寸为 0.5f。
|
||||
var tileWorldHalfSize = 0.5f; // 理想情况下,这应从 mapGenerator 或某个全局配置获取。
|
||||
|
||||
// 获取最左下角 (0,0) 瓦片的中心世界坐标
|
||||
Vector2 worldMinTileCenter = mapGenerator.GetWorldCoordinates(Vector3Int.zero);
|
||||
// 获取最右上角 (width-1, height-1) 瓦片的中心世界坐标
|
||||
Vector2 worldMaxTileCenter = mapGenerator.GetWorldCoordinates(new Vector3Int(mapGridSize.x - 1, mapGridSize.y - 1));
|
||||
|
||||
// 计算地图在世界坐标系中的绝对边界
|
||||
// 我们取 x,y 轴的最小值和最大值,确保正确的边界范围
|
||||
var worldMinX = worldMinTileCenter.x - tileWorldHalfSize;
|
||||
var worldMaxX = worldMaxTileCenter.x + tileWorldHalfSize;
|
||||
var worldMinY = worldMinTileCenter.y - tileWorldHalfSize;
|
||||
var worldMaxY = worldMaxTileCenter.y + tileWorldHalfSize;
|
||||
|
||||
// 限制位置在计算出的世界地图边界内
|
||||
var clampedPosition = worldPosition;
|
||||
clampedPosition.x = Mathf.Clamp(worldPosition.x, worldMinX, worldMaxX);
|
||||
clampedPosition.y = Mathf.Clamp(worldPosition.y, worldMinY, worldMaxY);
|
||||
// Z轴通常用于深度,此处保持不变
|
||||
|
||||
if (clampedPosition != worldPosition)
|
||||
{
|
||||
Debug.LogWarning($"生成位置 {worldPosition} (类型: {_config.LocationType}) 超出地图可玩区域边界,已限制为 {clampedPosition}。");
|
||||
}
|
||||
return clampedPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user