void ConnectPointsRecursive(FieldConnectPoint prevPoint, RiverPoint currentPoint, Dictionary <RiverPoint, FieldConnectPoint> connectPointMap, int pointLevel) { if (connectPointMap.TryGetValue(currentPoint, out FieldConnectPoint point) == false) { point = ToFieldConnectPoint(currentPoint); point.Index = points.Count; points.Add(point); connectPointMap.Add(currentPoint, point); int leftIndex = leftRightPoints.Count * 2; leftRightPoints.Add(new Vector3[] { vertices[leftIndex], vertices[leftIndex + 1] }); if (point.Index - prevPoint.Index > 1) { leftRightPoints.Add(new Vector3[] { vertices[leftIndex + 2], vertices[leftIndex + 3] }); pointLevels.Add(pointLevel - 1); pointLevels.Add(pointLevel); } else { pointLevels.Add(pointLevel); } prevPoint.SetConnection(point); point.SetConnection(prevPoint); List <RiverPoint> nextPoints = currentPoint.NextPoints; for (int i0 = 0; i0 < nextPoints.Count; ++i0) { ConnectPointsRecursive(point, nextPoints[i0], connectPointMap, pointLevel + 1); } } else { prevPoint.SetConnection(point); point.SetConnection(prevPoint); int leftIndex = leftRightPoints.Count * 2; leftRightPoints.Add(new Vector3[] { vertices[leftIndex], vertices[leftIndex + 1] }); pointLevels.Add(pointLevel); } }
/** * ポイントのリストを元に接続の処理を行う * @param pointList ポイントクラスのリスト * @param interval 繋がる座標感の幅 * @param inOrder 順番通りに繋げるフラグ。川のように座標が順番に生成されるような時にtrueにする * @param mergeSize 頂点を融合させる時の判定サイズ * @param ofsetSize 外周からのオフセットサイズ、外周からこのサイズ分内側でのみ接続を行う * @param random 接続する確率 * @param maxNum 接続する最大数。-1の場合は判定しない */ public void SetConnection(List <FieldConnectPoint> pointList, float interval, float chunkSize, Vector2Int numChunks, bool inOrder = false, float random = 1f, int maxNum = -1) { int index; float checkTheta = 0.707f; var min = new float[4]; var no = new int[4]; float itv = interval * interval; int randomCount = 0; float chunkSizeInternal = chunkSize; Vector2Int numChunksInternal = numChunks; if (interval <= chunkSize * 0.5f) { chunkSizeInternal = chunkSize * 0.5f; numChunksInternal *= 2; } var pointsMap = CreatePointsMap(pointList, chunkSizeInternal); var direction = new Vector3[4]; direction[0] = Vector3.forward; direction[1] = Vector3.back; direction[2] = Vector3.right; direction[3] = Vector3.left; for (int i0 = 0; i0 < pointList.Count; ++i0) { FieldConnectPoint currentPoint = pointList[i0]; List <Vector2Int> chunks = GetCandidateChunks(currentPoint.Position, chunkSizeInternal, numChunksInternal, interval); var targetPoints = new List <FieldConnectPoint>(); for (int i1 = 0; i1 < chunks.Count; ++i1) { if (pointsMap.TryGetValue(chunks[i1], out List <FieldConnectPoint> points) != false) { targetPoints.AddRange(points); } } if (maxNum >= 0 && maxNum <= randomCount) { /* ランダムで作る最大数に達しているので処理を終わる */ return; } float rand = (float)randomSystem.NextDouble(); if (rand > random) { /* ランダムに判定しない */ continue; } min[0] = itv; min[1] = itv; min[2] = itv; min[3] = itv; no[0] = -1; no[1] = -1; no[2] = -1; no[3] = -1; bool orderFlag = false; int count = currentPoint.ConnectionList.Count; if (count < 4) { for (int i1 = 0; i1 < targetPoints.Count; ++i1) { if (inOrder != false && count > 0) { /* 順番通りの場合は次の座標と判断する */ if (orderFlag == false) { if (i0 < i1) { break; } i1 = i0 + 1; if (i1 >= targetPoints.Count) { break; } orderFlag = true; } } if (i0 == i1) { /* 同じものは判定しない */ continue; } if (currentPoint.Type == PointType.kRoadAlongRiver) { if (targetPoints[i1].Type == PointType.kRoadAlongRiver) { /* 川沿いの道路は川と同じように前後の座標と結ぶようにする */ if (i1 != i0 + 1) { continue; } } else { /* 川沿いから繋ぐ場合は、川沿いの道路とだけ接続する */ continue; } } Vector3 sub = Vector3.zero; sub.x = targetPoints[i1].Position.x - currentPoint.Position.x; sub.z = targetPoints[i1].Position.z - currentPoint.Position.z; float length = sub.x * sub.x + sub.z * sub.z; if (length > itv) { /* 距離が離れているものは判定しない */ continue; } sub = sub.normalized; bool flg = false; for (int i2 = 0; i2 < 4; ++i2) { float theta = sub.x * direction[i2].x + sub.z * direction[i2].z; if (theta <= checkTheta) { /* 角度の条件を満たしていない */ continue; } if (min[i2] <= length) { /* すでに設定しているものより遠い */ continue; } min[i2] = length; no[i2] = i1; flg = true; } if (flg != false) { ++count; } if (inOrder != false) { if (orderFlag != false) { i1 = targetPoints.Count; } } } for (int i1 = 0; i1 < direction.Length; ++i1) { if (no[i1] < 0) { /* この方向に繋げる座標が無かった */ continue; } index = no[i1]; currentPoint.SetConnection(targetPoints[index]); targetPoints[index].SetConnection(currentPoint); } ++randomCount; } } /* 孤立している点は削除する */ for (int i0 = pointList.Count - 1; i0 >= 0; --i0) { if (pointList[i0].ConnectionList.Count == 0) { pointList.RemoveAt(i0); } } }