using System.Collections.Generic; using System.Linq; // 需要引用 Linq 进行排序 using UnityEngine; namespace SLSUtilities.Map { public class LayeredMapGenerator : MapGeneratorBase { [Header("分层生成设置")] [Tooltip("地图有多少层(环)")] public int layerCount = 3; [Tooltip("每一层的半径间距")] public float radiusStep = 5f; [Tooltip("每一层最少/最多生成多少个房间")] public Vector2Int nodesPerLayerRange = new Vector2Int(5, 8); // 建议最小值稍微调高一点 [Tooltip("位置随机偏移量")] public float positionJitter = 1.0f; [Header("连通性设置")] [Range(0f, 1f)] public float ringConnectChance = 1.0f; // 设为1方便调试环状结构 // 辅助数据:按层级索引 private Dictionary> nodesByLayer = new Dictionary>(); // 覆盖基类的 GenerateMap [ContextMenu("Generate Layered Map")] public override void GenerateMap() { base.ClearMap(); nodesByLayer.Clear(); GenerateNodesInLayers(); ConnectLayers(); } private void GenerateNodesInLayers() { int globalID = 0; // --- Layer 0 (Center) --- MapNode centerNode = new MapNode(globalID++, Vector2.zero, defaultNodeData); allNodes.Add(centerNode); nodesByLayer[0] = new List { centerNode }; List layerNodeCounts = new List(); for (int layerIndex = 1; layerIndex <= layerCount; layerIndex++) { layerNodeCounts.Add(Random.Range(nodesPerLayerRange.x, nodesPerLayerRange.y + 1)); } layerNodeCounts.Sort(); // 从小到大排序,确保外层节点数不少于内层 // --- Layer 1 to N --- for (int layerIndex = 1; layerIndex <= layerCount; layerIndex++) { List currentLayerNodes = new List(); int count = layerNodeCounts[layerIndex - 1]; float currentRadius = layerIndex * radiusStep; // 半径随层级增长略微加快 Debug.Log($"Layer {layerIndex}: Generating {count} nodes at radius {currentRadius}"); for (int i = 0; i < count; i++) { float angleStep = 360f / count; float currentAngle = (i * angleStep); // 先不加随机角度,靠 jitter 产生偏移 float radian = currentAngle * Mathf.Deg2Rad; // 基础极坐标位置 float x = Mathf.Cos(radian) * currentRadius; float y = Mathf.Sin(radian) * currentRadius; Vector2 basePos = new Vector2(x, y); // 加上 Jitter Vector2 finalPos = basePos + (Random.insideUnitCircle * positionJitter); MapNode newNode = new MapNode(globalID++, finalPos, defaultNodeData); allNodes.Add(newNode); currentLayerNodes.Add(newNode); } // 【关键优化点】:在生成完这一层所有点后,根据实际生成的“角度”重新排序 // 这样即使 Jitter 把点的位置打乱了,连接时依然是顺时针有序的,不会出现交叉 currentLayerNodes = currentLayerNodes.OrderBy(n => Mathf.Atan2(n.position.y, n.position.x) ).ToList(); nodesByLayer[layerIndex] = currentLayerNodes; } } private void ConnectLayers() { for (int layerIndex = 1; layerIndex <= layerCount; layerIndex++) { if (!nodesByLayer.ContainsKey(layerIndex)) continue; List currentLayer = nodesByLayer[layerIndex]; List previousLayer = nodesByLayer[layerIndex - 1]; for (int i = 0; i < currentLayer.Count; i++) { MapNode currentNode = currentLayer[i]; // 1. 向心连接 (Connect to inner layer) MapNode targetInner = FindClosestNode(currentNode, previousLayer); CreateEdge(currentNode, targetInner); // 2. 环状连接 (Ring Connection) if (Random.value <= ringConnectChance) { // 因为我们在生成时已经按 Atan2 排序了,所以 i+1 一定是几何上的相邻点 int nextIndex = (i + 1) % currentLayer.Count; MapNode neighborNode = currentLayer[nextIndex]; if (!ConnectionExists(currentNode, neighborNode)) { CreateEdge(currentNode, neighborNode); } } } } } private void CreateEdge(MapNode a, MapNode b) { // 简单的防重检查 if (!ConnectionExists(a, b)) { allEdges.Add(new MapEdge(a, b, true)); } } private bool ConnectionExists(MapNode a, MapNode b) { foreach (var edge in allEdges) { if ((edge.fromNode == a && edge.toNode == b) || (edge.fromNode == b && edge.toNode == a)) return true; } return false; } private MapNode FindClosestNode(MapNode source, List candidates) { MapNode bestTarget = null; float minDst = float.MaxValue; foreach (var target in candidates) { float dst = Vector2.Distance(source.position, target.position); if (dst < minDst) { minDst = dst; bestTarget = target; } } return bestTarget; } } }