int CreateRiver(HexCell origin) { int length = 1; HexCell cell = origin; HexDirection direction = HexDirection.NE; while (!cell.IsUnderwater) { int minNeighborElevation = int.MaxValue; flowDirections.Clear(); for (HexDirection d = HexDirection.NE; d <= HexDirection.NW; d++) { HexCell neighbor = cell.GetNeighbor(d); if (!neighbor) { continue; } if (neighbor.Elevation < minNeighborElevation) { minNeighborElevation = neighbor.Elevation; } if (neighbor == origin || neighbor.HasIncomingRiver) { continue; } int delta = neighbor.Elevation - cell.Elevation; if (delta > 0) { continue; } if (neighbor.HasOutgoingRiver) { cell.SetOutgoingRiver(d); return(length); } if (delta < 0) { flowDirections.Add(d); flowDirections.Add(d); flowDirections.Add(d); } if ( length == 1 || (d != direction.Next2() && d != direction.Previous2()) ) { flowDirections.Add(d); } flowDirections.Add(d); } if (flowDirections.Count == 0) { if (length == 1) { return(0); } if (minNeighborElevation >= cell.Elevation) { cell.WaterLevel = minNeighborElevation; if (minNeighborElevation == cell.Elevation) { cell.Elevation = minNeighborElevation - 1; } } break; } direction = flowDirections[Random.Range(0, flowDirections.Count)]; cell.SetOutgoingRiver(direction); length += 1; if ( minNeighborElevation >= cell.Elevation && Random.value < extaLakeProbability ) { cell.WaterLevel = cell.Elevation; cell.Elevation -= 1; } cell = cell.GetNeighbor(direction); } return(length); }
public int CreateRiver(HexCell riverOrigin) { int length = 0; HexCell hexCell = riverOrigin; HexDirection direction = HexDirection.NE; int minNeighbourElevation = int.MaxValue; while (!hexCell.IsUnderwater) { m_flowDirections.Clear(); for (HexDirection dir = HexDirection.NE; dir <= HexDirection.NW; dir++) { HexCell neighbour = hexCell.GetNeighbour(dir); if (neighbour == null) { continue; } if (neighbour.Elevation < minNeighbourElevation) { minNeighbourElevation = neighbour.Elevation; } if (neighbour == riverOrigin || neighbour.HasIncomingRiver) { continue; } int delta = neighbour.Elevation - hexCell.Elevation; if (delta > 0) { continue; } if (neighbour.HasOutgoingRiver) { hexCell.SetOutgoingRiver(dir); return(length); } if (length == 1 || (dir != direction.Next2() && dir != direction.Previous2())) { m_flowDirections.Add(dir); } // weight dowhills if (delta < 0) { m_flowDirections.Add(dir); m_flowDirections.Add(dir); m_flowDirections.Add(dir); } m_flowDirections.Add(dir); } if (m_flowDirections.Count == 0) { if (length == 1) { return(0); } if (minNeighbourElevation >= hexCell.Elevation) { hexCell.WaterLevel = minNeighbourElevation; if (minNeighbourElevation == hexCell.Elevation) { hexCell.Elevation = minNeighbourElevation - 1; } } break; } direction = m_flowDirections[Random.Range(0, m_flowDirections.Count)]; hexCell.SetOutgoingRiver(direction); length += 1; if (minNeighbourElevation >= hexCell.Elevation && Random.value < ExtraLakeProability) { hexCell.WaterLevel = hexCell.Elevation; hexCell.Elevation--; } hexCell = hexCell.GetNeighbour(direction); } return(length); }
int CreateRiver(HexCell origin) { int downhillBonus = 3; // This is how much extra weight is given to rivers for // flowing downhill. If a hex of equal elevation has a // weight of 1, then a downhill hex has 1 + downhillBonus // weight int length = 1; HexCell cell = origin; HexDirection direction = HexDirection.NE; while (!cell.Terrain.IsUnderwater) { int minNeighborElevation = int.MaxValue; flowDirections.Clear(); for (HexDirection d = HexDirection.NE; d <= HexDirection.NW; d++) { HexCell neighbor = cell.GetNeighbor(d); if (!neighbor) { continue; } if (neighbor.Terrain.Elevation < minNeighborElevation) { minNeighborElevation = neighbor.Terrain.Elevation; } if (neighbor == origin || neighbor.Terrain.RiverTerrain.HasIncomingRiver) { continue; } int delta = neighbor.Terrain.Elevation - cell.Terrain.Elevation; if (delta > 0) { continue; } if (neighbor.Terrain.RiverTerrain.HasOutgoingRiver) { cell.Terrain.RiverTerrain.SetOutgoingRiver(d); return(length); } if (delta < 0) { for (int i = 0; i < downhillBonus; i++) { flowDirections.Add(d); } } if (length == 1 || (d != direction.Next2() && d != direction.Previous2()) ) { flowDirections.Add(d); } flowDirections.Add(d); } if (flowDirections.Count == 0) { if (length == 1) { return(0); } if (minNeighborElevation >= cell.Terrain.Elevation) { cell.Terrain.WaterLevel = minNeighborElevation; if (minNeighborElevation == cell.Terrain.Elevation) { cell.Terrain.Elevation = minNeighborElevation - 1; } } break; } direction = flowDirections[Random.Range(0, flowDirections.Count)]; cell.Terrain.RiverTerrain.SetOutgoingRiver(direction); length += 1; if (minNeighborElevation >= cell.Terrain.Elevation && Random.value < extraLakeProbability) { cell.Terrain.WaterLevel = cell.Terrain.Elevation; cell.Terrain.Elevation -= 1; } cell = cell.GetNeighbor(direction); } return(length); }
void TriangulateWithRiver(HexDirection direction, HexCell cell) { var center = cell.Center; var closerEdge = cell.Edges[(int)direction]; if (cell.HasRiverThroughEdge(direction.Next())) { if (cell.HasRiverThroughEdge(direction.Previous())) { center += HexMetrics.GetSolidEdgeMiddle(direction) * (HexMetrics.InnerToOuter * 0.5f); } else if (cell.HasRiverThroughEdge(direction.Previous2())) { center += HexMetrics.GetLeftSolidCorner(direction) * 0.25f; } } else if (cell.HasRiverThroughEdge(direction.Previous()) && cell.HasRiverThroughEdge(direction.Next2())) { center += HexMetrics.GetRightSolidCorner(direction) * 0.25f; } Vector3 centerL, centerR; if (cell.HasRiverThroughEdge(direction.Opposite())) { centerL = center + HexMetrics.GetLeftSolidCorner(direction.Previous()) * 0.25f; centerR = center + HexMetrics.GetRightSolidCorner(direction.Next()) * 0.25f; } else if (cell.HasRiverThroughEdge(direction.Next())) { centerL = center; centerR = Vector3.Lerp(center, closerEdge.V5, 0.65f); } else if (cell.HasRiverThroughEdge(direction.Previous())) { centerL = Vector3.Lerp(center, closerEdge.V1, 0.65f); centerR = center; } else if (cell.HasRiverThroughEdge(direction.Next2())) { centerL = center; centerR = center + HexMetrics.GetSolidEdgeMiddle(direction.Next()) * (0.5f * HexMetrics.InnerToOuter); } else { centerL = center + HexMetrics.GetSolidEdgeMiddle(direction.Previous()) * (0.5f * HexMetrics.InnerToOuter); centerR = center; } // after deciding where the left and right points are, we can determine the final center by averaging them center = Vector3.Lerp(centerL, centerR, 0.5f); var m = new EdgeVertices(Vector3.Lerp(centerL, closerEdge.V1, 0.5f), Vector3.Lerp(centerR, closerEdge.V5, 0.5f), 1f / 12f); m.V3.y = closerEdge.V3.y; // external hex circle TriangulateEdgeStrip(m, cell.Color, closerEdge, cell.Color); // connection between hexes Terrain.AddTriangle(centerL, m.V1, m.V2); Terrain.AddTriangleColor(cell.Color); Terrain.AddQuad(centerL, new Vector3(center.x, cell.StreamBedY, center.z), m.V2, m.V3); Terrain.AddQuadColor(cell.Color); Terrain.AddQuad(new Vector3(center.x, cell.StreamBedY, center.z), centerR, m.V3, m.V4); Terrain.AddQuadColor(cell.Color); Terrain.AddTriangle(centerR, m.V4, m.V5); Terrain.AddTriangleColor(cell.Color); // create river quads if (!cell.IsUnderwater) { bool reversed = cell.IncomingRiver == direction; // inner fan of the hex TriangulateRiverQuadUnperturbed(centerL, centerR, m.V2, m.V4, cell.RiverSurfaceY, 0.4f, reversed); // external circle of the hex var neighbor = cell.GetNeighbor(direction); if (neighbor.IsUnderwater) { TriangulateRiverQuadUnperturbed(m.V2, m.V4, closerEdge.V2, closerEdge.V4, cell.RiverSurfaceY, HexMetrics.WaterSurfaceY, 0.6f, reversed); } // normal connection between two rivers else { TriangulateRiverQuadUnperturbed(m.V2, m.V4, closerEdge.V2, closerEdge.V4, cell.RiverSurfaceY, 0.6f, reversed); } } }
private void TriangulateCultureCorners_FlatEdge( IHexCell center, IHexCell left, IHexCell right, IHexCell nextRight, HexDirection direction, ICivilization centerOwner, ReadOnlyCollection <Vector2> centerRightContour, ReadOnlyCollection <Vector2> rightCenterContour, IHexMesh cultureMesh ) { if (left != null && CivTerritoryLogic.GetCivClaimingCell(left) != centerOwner) { Color cultureColor = centerOwner.Template.Color; var centerLeftContour = CellEdgeContourCanon.GetContourForCellEdge(center, direction.Previous()); var rightLeftContour = CellEdgeContourCanon.GetContourForCellEdge(right, direction.Previous2()); Vector2 centerLeftFirstInner = Vector2.Lerp(centerLeftContour.First(), center.AbsolutePositionXZ, RenderConfig.CultureWidthPercent); Vector2 centerLeftLastInner = Vector2.Lerp(centerLeftContour.Last(), center.AbsolutePositionXZ, RenderConfig.CultureWidthPercent); Vector2 rightLeftFirstInner = Vector2.Lerp(rightLeftContour.First(), right.AbsolutePositionXZ, RenderConfig.CultureWidthPercent); Vector2 rightleftLastInner = Vector2.Lerp(rightLeftContour.Last(), right.AbsolutePositionXZ, RenderConfig.CultureWidthPercent); Vector2 rayAlongCenterLeft = (centerLeftLastInner - centerLeftFirstInner).normalized; Vector2 rayAlongRightLeft = (rightLeftFirstInner - rightleftLastInner).normalized; Vector2 bezierControl; if (!Geometry2D.ClosestPointsOnTwoLines( centerLeftLastInner, rayAlongCenterLeft, rightLeftFirstInner, rayAlongRightLeft, out bezierControl, out bezierControl )) { Debug.LogError("TriangulateCultureCorners_FlatEdge failed to find a valid control point"); return; } Vector3 pivotXYZ = new Vector3(centerLeftContour.Last().x, 0f, centerLeftContour.Last().y); float paramDelta = 5f / RenderConfig.RiverQuadsPerCurve; for (float t = 0; t < 1f; t = Mathf.Clamp01(t + paramDelta)) { float nextT = Mathf.Clamp01(t + paramDelta); Vector2 bezierOne = BezierQuadratic.GetPoint(centerLeftLastInner, bezierControl, rightLeftFirstInner, nextT); Vector2 bezierTwo = BezierQuadratic.GetPoint(centerLeftLastInner, bezierControl, rightLeftFirstInner, t); cultureMesh.AddTriangle(pivotXYZ, new Vector3(bezierOne.x, 0f, bezierOne.y), new Vector3(bezierTwo.x, 0f, bezierTwo.y)); cultureMesh.AddTriangleUV(new Vector2(0f, 1f), Vector2.zero, Vector2.zero); cultureMesh.AddTriangleColor(cultureColor); } if (rightCenterContour.Count == 3) { Vector2 innerPoint = Vector2.Lerp(rightCenterContour.Last(), right.AbsolutePositionXZ, RenderConfig.CultureWidthPercent); Vector2 secondToLastContour = rightCenterContour[rightCenterContour.Count - 2]; Vector2 lastContour = rightCenterContour.Last(); cultureMesh.AddTriangle( new Vector3(innerPoint.x, 0f, innerPoint.y), new Vector3(secondToLastContour.x, 0f, secondToLastContour.y), new Vector3(lastContour.x, 0f, lastContour.y) ); cultureMesh.AddTriangleUV(new Vector2(0f, 0f), new Vector2(0f, 1f), new Vector2(0f, 1f)); cultureMesh.AddTriangleColor(cultureColor); } } }