Esempio n. 1
0
    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);
    }
Esempio n. 2
0
    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);
    }
Esempio n. 3
0
    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);
    }
Esempio n. 4
0
    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);
            }
        }
    }
Esempio n. 5
0
        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);
                }
            }
        }