using UnityEngine; using UnityEngine.Tilemaps; using Newtonsoft.Json; using System.Collections.Generic; using System.Threading.Tasks; using Data; using Managers; namespace Map { public class BuildingGeneratorConfig { [JsonProperty("defName")] public string DefName { get; set; } // 图案定义名称 [JsonProperty("mapping")] public Dictionary Mapping; // 图案值到定义名称的映射 [JsonProperty("pattern")] public int[,] Pattern { get; set; } // 建筑图案 [JsonProperty("baseTileDefName")] public string BaseTileDefName { get; set; } // 基底所需瓦片的定义名称 [JsonProperty("autoExpand")] public bool AutoExpand { get; set; } // 是否自动扩展搜索区域 [JsonProperty("positionX", Required = Required.Always)] public int PositionX { get; set; } // 起始位置X坐标 [JsonProperty("positionY", Required = Required.Always)] public int PositionY { get; set; } // 起始位置Y坐标 } public class BuildingMapGenerator : MapGeneratorWorkClassBase { private BuildingGeneratorConfig _config; private string _requiredBaseTileName; // 缓存基底瓦片TileBase的运行时名称 /// /// 初始化建筑生成器,解析JSON配置。 /// /// 包含BuildingGeneratorConfig的JSON字符串。 public override void Init(string value) { if (string.IsNullOrEmpty(value)) { Debug.LogError("建筑生成器: Init接收到空或null的JSON值。"); return; } try { _config = JsonConvert.DeserializeObject(value); if (_config == null) { Debug.LogError("建筑生成器: 无法从JSON反序列化BuildingGeneratorConfig。"); return; } // 预加载基底瓦片定义 if (string.IsNullOrEmpty(_config.BaseTileDefName)) return; var baseAsset = TileManager.Instance.GetTile(_config.BaseTileDefName); if (baseAsset != null) { _requiredBaseTileName = baseAsset.name; // 缓存TileBase的运行时名称 } else { Debug.LogWarning( $"建筑生成器: 通过TileManager未找到定义'{_config.BaseTileDefName}'的基底瓦片资产。"); } } catch (JsonException ex) { Debug.LogError($"建筑生成器: JSON反序列化错误: {ex.Message}\nJSON: {value}"); } } /// /// 获取建筑生成器将影响的区域大小。 /// /// 表示区域宽和高的Vector2Int。 public override Vector2Int GetSize() { if (_config == null) { return Vector2Int.zero; } if (_config.Pattern != null) { return new Vector2Int(_config.Pattern.GetLength(1), _config.Pattern.GetLength(0)); // GetLength(1)是宽度,GetLength(0)是高度 } else { // 如果没有图案,默认为单格建筑 return new Vector2Int(1, 1); } } /// /// 执行建筑生成逻辑。 /// /// MapGenerator实例,提供Tilemap和坐标转换功能。 public override async Task Process(Landform landform) { if (_config == null) // 错误已在Init中记录,或者Init未被调用。 return; if (landform == null || landform.buildingTilemap == null || landform.baseTilemap == null) { Debug.LogError("建筑生成器: MapGenerator或其Tilemap未赋值。"); return; } var patternSize = GetSize(); if (patternSize == Vector2Int.zero) { Debug.LogWarning("建筑生成器: 图案大小为零,未生成任何内容。"); return; } var actualStartPosition = new Vector2Int(_config.PositionX, _config.PositionY); // 检查是否有要求基底瓦片,并且已经成功获取到基底瓦片的运行时名称 if (!string.IsNullOrEmpty(_config.BaseTileDefName) && !string.IsNullOrEmpty(_requiredBaseTileName)) { // 检查当前指定位置是否满足基底条件 var baseSatisfied = CheckBaseTileCondition(landform.baseTilemap, actualStartPosition, patternSize, _requiredBaseTileName); if (!baseSatisfied && _config.AutoExpand) { // 如果不满足且允许自动扩展,则搜索新的有效起始位置 var foundPos = FindSuitableStartPosition(landform.baseTilemap, actualStartPosition, patternSize, _requiredBaseTileName, searchRadius: 5); // 搜索半径可配置 if (foundPos.HasValue) { actualStartPosition = foundPos.Value; } else { Debug.LogWarning( $"建筑生成器: 无法为'{_config.DefName ?? "图案"}'在基底'{_requiredBaseTileName}'上找到合适的基底瓦片位置,已进行自动扩展。"); return; // 无法找到合适位置,跳过生成 } } else if (!baseSatisfied && !_config.AutoExpand) { Debug.LogWarning( $"建筑生成器: 基底瓦片条件'{_requiredBaseTileName}'在({actualStartPosition.x}, {actualStartPosition.y})处不满足,且autoExpand为false。跳过生成。"); return; // 不满足且不允许扩展,跳过生成 } } else if (!string.IsNullOrEmpty(_config.BaseTileDefName) && string.IsNullOrEmpty(_requiredBaseTileName)) { Debug.LogWarning( $"建筑生成器: 已指定基底瓦片定义('{_config.BaseTileDefName}'),但通过TileManager未找到其资产。跳过基底条件检查。"); } // 遍历图案并生成建筑 if (_config.Pattern != null) { for (var y = 0; y < patternSize.y; y++) // 行 (height) { for (var x = 0; x < patternSize.x; x++) // 列 (width) { var patternValue = _config.Pattern[y, x]; if (patternValue == 0) // 0通常表示空,不生成 { continue; } if (_config.Mapping == null || !_config.Mapping.TryGetValue(patternValue, out var defName)) { Debug.LogWarning( $"建筑生成器: 图案值{patternValue}在相对位置({x},{y})没有映射。跳过。"); continue; } // 计算当前建筑单元的世界/网格坐标 var currentGridPos = new Vector3Int(actualStartPosition.x + x, actualStartPosition.y + y, 0); // 网格坐标与 position(X, Y) 对应 var currentWorldPos = landform.GetWorldCoordinates(currentGridPos); await GenerateIndividualBuilding(landform, defName, currentGridPos, currentWorldPos); } } } else if (!string.IsNullOrEmpty(_config.DefName)) { // 如果没有图案,生成单个建筑 var currentGridPos = new Vector3Int(actualStartPosition.x, actualStartPosition.y, 0); var currentWorldPos = landform.GetWorldCoordinates(currentGridPos); await GenerateIndividualBuilding(landform, _config.DefName, currentGridPos, currentWorldPos); } else { Debug.LogWarning("建筑生成器: 配置中未指定图案或DefName。未生成任何内容。"); } } /// /// 生成单个建筑(瓦片或实体)。 /// /// MapGenerator实例。 /// 建筑定义名称。 /// 建筑的网格位置。 /// 建筑的世界位置。 private async Task GenerateIndividualBuilding(Landform landform, string defName, Vector3Int gridPos, Vector3 worldPos) { var buildingDef = DefineManager.Instance.FindDefine(defName); if (buildingDef == null) { Debug.LogWarning($"建筑生成器: 未找到建筑定义'{defName}'。"); return; } if (buildingDef.buildingType == BuildingType.Static) { if (buildingDef.tile != null && !string.IsNullOrEmpty(buildingDef.tile.defName)) { var tileToPlace = TileManager.Instance.GetTile(buildingDef.tile.defName); if (tileToPlace != null) { landform.buildingTilemap.SetTile(gridPos, tileToPlace); // Debug.Log($"建筑生成器: 在网格位置{gridPos}放置了静态建筑'{defName}'('{buildingDef.tile.defName}')。"); } else { Debug.LogWarning( $"建筑生成器: 未找到静态建筑'{defName}'的瓦片资产('{buildingDef.tile.defName}')。跳过。"); } } else { Debug.LogWarning( $"建筑生成器: 静态建筑'{defName}'没有有效的TileDef或其defName为空。跳过。"); } } else if (buildingDef.buildingType == BuildingType.Dynamic) { EntityManager.Instance.GenerateBuildingEntity(landform.GetDimensionID(), buildingDef, worldPos); // Debug.Log($"建筑生成器: 在世界位置{worldPos}生成了动态建筑实体'{defName}'。"); } await Task.Yield(); // 异步操作,避免阻塞 } /// /// 检查给定区域的基底瓦片条件是否满足。 /// /// 基底瓦片地图。 /// 区域的起始网格位置 (X, Y)。 /// 区域的尺寸 (宽, 高)。 /// 要求的基底瓦片运行时名称。 /// 如果整个区域都满足基底瓦片条件,则返回true。 private bool CheckBaseTileCondition(Tilemap baseTilemap, Vector2Int startPos, Vector2Int size, string requiredTileBaseName) { if (string.IsNullOrEmpty(requiredTileBaseName)) { Debug.LogWarning( "建筑生成器: 所需基底瓦片资产名称为空。基底条件检查已跳过或失败。"); return false; } for (var y = 0; y < size.y; y++) { for (var x = 0; x < size.x; x++) { var currentCheckPos = new Vector3Int(startPos.x + x, startPos.y + y, 0); var tileBase = baseTilemap.GetTile(currentCheckPos); if (tileBase == null || !tileBase.name.Equals(requiredTileBaseName)) return false; // 任何一个位置不满足则整个区域不满足 } } return true; } /// /// 在给定范围内搜索适合放置建筑的起始位置。 /// 使用广度优先搜索 (BFS) 算法。 /// /// 基底瓦片地图。 /// 最初指定的起始位置。 /// 建筑图案的尺寸。 /// 要求的基底瓦片运行时名称。 /// 搜索的最大半径(从原始起始位置的曼哈顿距离)。 /// 找到的第一个适合的起始位置,如果没有找到则为 null。 private Vector2Int? FindSuitableStartPosition(Tilemap baseTilemap, Vector2Int originalStartPos, Vector2Int patternSize, string requiredTileBaseName, int searchRadius) { var queue = new Queue(); var visited = new HashSet(); queue.Enqueue(originalStartPos); visited.Add(originalStartPos); while (queue.Count > 0) { var currentPos = queue.Dequeue(); // 检查当前位置是否满足条件 if (CheckBaseTileCondition(baseTilemap, currentPos, patternSize, requiredTileBaseName)) { return currentPos; } // 探索邻近位置 Vector2Int[] directions = { new Vector2Int(0, 1), // 上 new Vector2Int(0, -1), // 下 new Vector2Int(1, 0), // 右 new Vector2Int(-1, 0) // 左 }; foreach (var dir in directions) { var nextPos = new Vector2Int(currentPos.x + dir.x, currentPos.y + dir.y); // 检查是否在搜索半径内 (曼哈顿距离) if (Mathf.Abs(nextPos.x - originalStartPos.x) + Mathf.Abs(nextPos.y - originalStartPos.y) > searchRadius) { continue; // 超出搜索范围 } if (!visited.Contains(nextPos)) { visited.Add(nextPos); queue.Enqueue(nextPos); } } } return null; // 未找到合适位置 } } }