FieldConnectPoint ToFieldConnectPoint(RiverPoint riverPoint) { var point = new FieldConnectPoint(); point.Initialize(riverPoint.Position, PointType.kRiver); return(point); }
void AbsorbPoint(RiverPoint currentPoint, RiverPoint absorptionPoint) { Vector3 currentPos = currentPoint.Position; List <RiverPoint> nextPoints = currentPoint.NextPoints; if (nextPoints.Contains(absorptionPoint) == false) { nextPoints.Add(absorptionPoint); Vector3 normDir = (absorptionPoint.Position - currentPos).normalized; float halfWidth = width * 0.5f; var leftBase = new Vector3(-normDir.z, 0, normDir.x) * halfWidth; var rightBase = new Vector3(normDir.z, 0, -normDir.x) * halfWidth; Vector3 left = leftBase + currentPos; Vector3 right = rightBase + currentPos; vertices.Add(left); vertices.Add(right); } List <RiverPoint> prevPoints = absorptionPoint.PrevPoints; if (prevPoints.Contains(currentPoint) == false) { prevPoints.Add(currentPoint); } }
void AddToPointMap(RiverPoint point) { Vector2Int chunk = GetChunk(point.Position); List <RiverPoint> pointsInChunk; if (riverPointsMap.TryGetValue(chunk, out pointsInChunk) == false) { pointsInChunk = new List <RiverPoint>(); riverPointsMap.Add(chunk, pointsInChunk); } if (pointsInChunk.Contains(point) == false) { pointsInChunk.Add(point); } }
void GenerateRoadAlongRiver(RiverPoint riverRoot) { roadAlongRiverPoints.Clear(); leftRoadPoints.Clear(); rightRoadPoints.Clear(); for (int i0 = 0; i0 < riverRoot.NextPoints.Count; ++i0) { GenerateRoadAlongRiverRecursive(riverRoot, null, riverRoot.NextPoints[i0], false, false); } roadAlongRiverPoints.AddRange(leftRoadPoints); roadAlongRiverPoints.AddRange(rightRoadPoints); points.AddRange(roadAlongRiverPoints); }
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); } }
void GenerateRiverRecursive(RiverPoint riverPoint, Vector3 dir, float bendability) { RiverPoint currentPoint = riverPoint; Vector3 currentPos = currentPoint.Position; Vector3 nextDir = dir; int numStep = 0; int totalStep = 0; float bend = bendability; float angleRange = parameter.AngleRange; float halfWidth = width * 0.5f; float stepSize = parameter.StepSize; var step = new Vector3(0, 0, stepSize); while (IsInsideField(currentPos) != false) { ++numStep; ++totalStep; Vector3 nextPos = currentPos + nextDir; Vector2Int currentChunk = GetChunk(currentPos); Vector2Int nextChunk = GetChunk(nextPos); RiverPoint absorptionPoint = null; if (TryGetAbsorptionPoint(currentPos, nextPos, currentChunk, stepSize * 0.5f, out absorptionPoint) != false) { AbsorbPoint(currentPoint, absorptionPoint); currentPoint = absorptionPoint; currentPos = currentPoint.Position; break; } else if (currentChunk != nextChunk && TryGetAbsorptionPoint(currentPos, nextPos, nextChunk, stepSize * 0.5f, out absorptionPoint) != false) { AbsorbPoint(currentPoint, absorptionPoint); currentPoint = absorptionPoint; currentPos = currentPoint.Position; break; } else { float angle = Mathf.Atan2(nextDir.x, nextDir.z) * Mathf.Rad2Deg; if (canBranch != false && numStep >= numStepWithoutBranching) { if (DetectFromPercent(branchingProbability) != false) { numStep = 0; branchingProbability = CalcBranchingProbability(); numStepWithoutBranching = CalcNumStepWithoutBranching(); float angle2 = angle + Mathf.Lerp(minAngleForBranching, angleRange, (float)random.NextDouble()) * (random.Next(2) == 0 ? -1 : 1); Vector3 nextDir2 = Quaternion.Euler(0, angle2, 0) * step; GenerateRiverRecursive(currentPoint, nextDir2, bend); } } var nextPoint = new RiverPoint(); nextPoint.Position = nextPos; nextPoint.Width = width; nextPoint.PrevPoints.Add(currentPoint); currentPoint.NextPoints.Add(nextPoint); AddToPointMap(nextPoint); Vector3 normDir = nextDir.normalized; var leftBase = new Vector3(-normDir.z, 0, normDir.x) * halfWidth; var rightBase = new Vector3(normDir.z, 0, -normDir.x) * halfWidth; Vector3 left = leftBase + currentPos; Vector3 right = rightBase + currentPos; vertices.Add(left); vertices.Add(right); float nextAngle = angle + angleRange * (float)random.NextDouble() - angleRange * 0.5f; bend *= (1.0f - parameter.BendabilityAttenuation); nextAngle = Mathf.Lerp(angle, nextAngle, bend); nextDir = Quaternion.Euler(0, nextAngle, 0) * step; currentPoint = nextPoint; currentPos = currentPoint.Position; } } if (totalStep != 0) { Vector3 normDir = nextDir.normalized; Vector3 left = new Vector3(-normDir.z, 0, normDir.x) * halfWidth + currentPos; Vector3 right = new Vector3(normDir.z, 0, -normDir.x) * halfWidth + currentPos; vertices.Add(left); vertices.Add(right); } }
public void Generate(RiverParameter parameter, System.Random random) { lastInterruptionTime = System.DateTime.Now; this.parameter = parameter; this.random = random; width = Mathf.Lerp(parameter.MinInitialWidth, parameter.MaxInitialWidth, (float)random.NextDouble()); branchingProbability = CalcBranchingProbability(); numStepWithoutBranching = CalcNumStepWithoutBranching(); points.Clear(); vertices.Clear(); riverPointsMap.Clear(); leftRightPoints.Clear(); pointLevels.Clear(); quadranglesMap.Clear(); Vector3 initialPosition = DecideInitialPosition(); float initialAngle = DecideInitialAngle(initialPosition); rootPoint = new RiverPoint(); rootPoint.Position = initialPosition; rootPoint.Width = width; AddToPointMap(rootPoint); var step = new Vector3(0, 0, parameter.StepSize); Vector3 initialDir = Quaternion.Euler(0, initialAngle, 0) * step; minAngleForBranching = Mathf.Atan2(width * 0.5f, parameter.StepSize) * Mathf.Rad2Deg * 2; canBranch = parameter.AngleRange >= minAngleForBranching; GenerateRiverRecursive(rootPoint, initialDir, 1); ConnectPoints(); for (int i0 = 0; i0 < leftRightPoints.Count - 1; ++i0) { if (pointLevels[i0 + 1] - pointLevels[i0] == 1) { Vector3 point1, point2, point3, point4; point1 = leftRightPoints[i0][0]; point2 = leftRightPoints[i0 + 1][0]; point3 = leftRightPoints[i0 + 1][1]; point4 = leftRightPoints[i0][1]; Vector2Int chunk1, chunk2, chunk3, chunk4; chunk1 = GetChunk(point1); chunk2 = GetChunk(point2); chunk3 = GetChunk(point3); chunk4 = GetChunk(point4); var chunks = new List <Vector2Int>(); chunks.Add(chunk1); if (chunk2 != chunk1) { chunks.Add(chunk2); } if (chunk3 != chunk1 && chunk3 != chunk2) { chunks.Add(chunk3); } if (chunk4 != chunk1 && chunk4 != chunk2 && chunk4 != chunk3) { chunks.Add(chunk4); } for (int i1 = 0; i1 < chunks.Count; ++i1) { Vector2Int chunk = chunks[i1]; List <Vector3[]> quadrangles; if (quadranglesMap.TryGetValue(chunk, out quadrangles) == false) { quadrangles = new List <Vector3[]>(); quadranglesMap.Add(chunk, quadrangles); } quadrangles.Add(new Vector3[] { point1, point2, point3, point4 }); } } } }
bool TryGetAbsorptionPoint(Vector3 startPos, Vector3 endPos, Vector2Int chunk, float distance, out RiverPoint absorptionPoint) { bool foundPoint = false; absorptionPoint = null; bool isIntersecting = false; var nearestPoint = new KeyValuePair <float, RiverPoint>(float.MaxValue, null); if (riverPointsMap.TryGetValue(chunk, out List <RiverPoint> pointsInChunk) != false) { for (int i0 = 0; i0 < pointsInChunk.Count; ++i0) { RiverPoint currentPoint = pointsInChunk[i0]; Vector3 currentPos = currentPoint.Position; var intersection = new Vector3(); List <RiverPoint> prevPoints = currentPoint.PrevPoints; for (int i1 = 0; i1 < prevPoints.Count; ++i1) { RiverPoint prevPoint = prevPoints[i1]; Vector3 prevPos = prevPoint.Position; if (IsIntersectingLineSegment(startPos, endPos, prevPos, currentPos) != false) { isIntersecting = true; foundPoint = true; TryGetIntersection(startPos, endPos, prevPos, currentPos, out intersection); float dist1 = (prevPos - intersection).sqrMagnitude; float dist2 = (currentPos - intersection).sqrMagnitude; absorptionPoint = dist1 < dist2 ? prevPoint : currentPoint; break; } else { float dist1 = (prevPos - endPos).sqrMagnitude; float dist2 = (currentPos - endPos).sqrMagnitude; if (dist1 < nearestPoint.Key) { nearestPoint = new KeyValuePair <float, RiverPoint>(dist1, prevPoint); } if (dist2 < nearestPoint.Key) { nearestPoint = new KeyValuePair <float, RiverPoint>(dist2, currentPoint); } } } List <RiverPoint> nextPoints = currentPoint.NextPoints; for (int i1 = 0; i1 < nextPoints.Count; ++i1) { RiverPoint nextPoint = nextPoints[i1]; Vector3 nextPos = nextPoint.Position; if (IsIntersectingLineSegment(startPos, endPos, currentPos, nextPos) != false) { isIntersecting = true; foundPoint = true; TryGetIntersection(startPos, endPos, currentPos, nextPos, out intersection); float dist1 = (currentPos - intersection).sqrMagnitude; float dist2 = (nextPos - intersection).sqrMagnitude; absorptionPoint = dist1 < dist2 ? currentPoint : nextPoint; break; } else { float dist1 = (currentPos - endPos).sqrMagnitude; float dist2 = (nextPos - endPos).sqrMagnitude; if (dist1 < nearestPoint.Key) { nearestPoint = new KeyValuePair <float, RiverPoint>(dist1, currentPoint); } if (dist2 < nearestPoint.Key) { nearestPoint = new KeyValuePair <float, RiverPoint>(dist2, nextPoint); } } } if (isIntersecting != false) { break; } } } if (isIntersecting == false) { if (nearestPoint.Key < distance * distance) { absorptionPoint = nearestPoint.Value; foundPoint = true; } } return(foundPoint); }
void GenerateRoadAlongRiverRecursive(RiverPoint currentPoint, RiverPoint prevPoint, RiverPoint nextPoint, bool addedLeftPoint, bool addedRightPoint) { Vector3 pos = currentPoint.Position; Vector3 nextPos = nextPoint.Position; Vector3 dir = nextPos - pos; Vector3 prevDir = prevPoint != null ? pos - prevPoint.Position : dir; float angle = Mathf.Atan2(dir.x, dir.z) * Mathf.Rad2Deg; Quaternion rotation = Quaternion.Euler(0, angle, 0); float dist = currentPoint.Width * 0.5f + parameter.DistanceFromRiver + parameter.Width * 0.5f; var leftBase = new Vector3(-dist, 0, 0); var rightBase = new Vector3(dist, 0, 0); float cross = Vector3.Cross(prevDir, dir).y; bool addedL = false; bool addedR = false; if (addedLeftPoint == false || cross > 0) { Vector3 left = rotation * leftBase + pos; if (river.Covers(left) == false) { var leftPoint = new FieldPoint { Position = left, Type = PointType.kRoadAlongRiver, }; leftRoadPoints.Add(leftPoint); AddToPointMap(leftPoint); addedL = true; } } if (addedRightPoint == false || cross < 0) { Vector3 right = rotation * rightBase + pos; if (river.Covers(right) == false) { var rightPoint = new FieldPoint { Position = right, Type = PointType.kRoadAlongRiver, }; rightRoadPoints.Add(rightPoint); AddToPointMap(rightPoint); addedR = true; } } if (nextPoint.NextPoints.Count > 0) { for (int i0 = 0; i0 < nextPoint.NextPoints.Count; ++i0) { GenerateRoadAlongRiverRecursive(nextPoint, currentPoint, nextPoint.NextPoints[i0], addedL, addedR); } } else { Vector3 nextLeft = rotation * leftBase + nextPos; if (river.Covers(nextLeft) == false) { var leftPoint2 = new FieldPoint { Position = nextLeft, Type = PointType.kRoadAlongRiver, }; leftRoadPoints.Add(leftPoint2); AddToPointMap(leftPoint2); } Vector3 nextRight = rotation * rightBase + nextPos; if (river.Covers(nextRight) == false) { var rightPoint2 = new FieldPoint { Position = nextRight, Type = PointType.kRoadAlongRiver, }; rightRoadPoints.Add(rightPoint2); AddToPointMap(rightPoint2); } } }