Ejemplo n.º 1
0
        private void TriangulateWithoutRiver(HexDirection direction, HexCell cell, Vector3 centre, EdgeVertices e)
        {
            TriangulateEdgeFan(cell.Position, e, cell.Index);

            if (cell.HasRoads)
            {
                var interpolators = GetRoadInterpolators(direction, cell);
                TriangulateRoad(centre,
                                Vector3.Lerp(centre, e.v1, interpolators.x), Vector3.Lerp(centre, e.v5, interpolators.y),
                                e, cell.HasRoadThroughEdge(direction), cell.Index);
            }
        }
Ejemplo n.º 2
0
        // triangulates one of the six cores of a hex cell
        // and, if the conditions are met, the bridge and corner on that side
        private void TriangulateCellDirection(HexDirection direction, HexCell cell)
        {
            var e = new EdgeVertices(
                cell.Position + HexMetrics.GetFirstSolidCorner(direction),
                cell.Position + HexMetrics.GetSecondSolidCorner(direction)
                );

            if (!cell.IsUnderwater && cell.HasRiver)
            {
                if (cell.HasRiverThroughEdge(direction))
                {
                    e.v3.y = cell.StreamBedY;
                    if (cell.HasRiverBeginOrEnd)
                    {
                        TriangulateWithRiverBeginOrEnd(direction, cell, cell.Position, e);
                    }
                    else
                    {
                        TriangulateWithRiver(direction, cell, cell.Position, e);
                    }
                }
                else
                {
                    TriangulateAdjacentToRiver(direction, cell, cell.Position, e);
                }
            }
            else
            {
                TriangulateWithoutRiver(direction, cell, cell.Position, e);

                if (!cell.IsUnderwater && !cell.HasRoadThroughEdge(direction))
                {
                    Features.AddFeature(cell, (cell.Position + e.v1 + e.v5) * (1f / 3));
                }
            }

            if (direction <= HexDirection.SE)
            {
                TriangulateConnection(direction, cell, e);
            }

            if (cell.IsUnderwater)
            {
                TriangulateWater(direction, cell, cell.Position);
            }
        }
Ejemplo n.º 3
0
        private void TriangulateRoadAdjacentToRiver(HexDirection direction, HexCell cell, Vector3 centre, EdgeVertices e)
        {
            var edgeRoad      = cell.HasRoadThroughEdge(direction);
            var previousRiver = cell.HasRiverThroughEdge(direction.Previous());
            var nextRiver     = cell.HasRiverThroughEdge(direction.Next());

            var interpolators = GetRoadInterpolators(direction, cell);
            var roadCentre    = centre;

            if (cell.HasRiverBeginOrEnd) // pointy end of rivers
            {
                roadCentre += HexMetrics.GetSolidEdgeMiddle(cell.RiverBeginOrEndDirection.Opposite()) * 1f / 3;
            }
            else if (cell.IncomingRiver == cell.OutgoingRiver.Opposite()) // straight rivers
            {
                Vector3 corner;
                if (previousRiver)
                {
                    if (!edgeRoad && !cell.HasRoadThroughEdge(direction.Next()))
                    {
                        return; // isolated on one side of the river
                    }
                    corner = HexMetrics.GetSecondSolidCorner(direction);
                }
                else
                {
                    if (!edgeRoad && !cell.HasRoadThroughEdge(direction.Previous()))
                    {
                        return; // isolated on one side of the river
                    }
                    corner = HexMetrics.GetFirstSolidCorner(direction);
                }

                roadCentre += corner / 2;
                if (cell.IncomingRiver == direction.Next() &&
                    (cell.HasRoadThroughEdge(direction.Next2()) ||
                     cell.HasRoadThroughEdge(direction.Opposite())))
                {
                    Features.AddBridge(roadCentre, centre - corner / 2);
                }
                centre += corner / 4;
            }
            else if (cell.IncomingRiver == cell.OutgoingRiver.Previous()) // zigzag river orientation 1
            {
                roadCentre -= HexMetrics.GetSecondSolidCorner(cell.IncomingRiver) * 0.2f;
            }
            else if (cell.IncomingRiver == cell.OutgoingRiver.Next()) // zigzag river orientation 2
            {
                roadCentre -= HexMetrics.GetFirstSolidCorner(cell.IncomingRiver) * 0.2f;
            }
            else if (previousRiver && nextRiver) // inside of curved river
            {
                if (!edgeRoad)
                {
                    return; // isolated road - i.e road didn't come from this edge, and doesn't connect out either.
                }
                var offset = HexMetrics.GetSolidEdgeMiddle(direction) * HexMetrics.InnerToOuter;
                roadCentre += offset * 0.7f;
                centre     += offset / 2;
            }
            else // outside of curved river
            {
                HexDirection middle;
                if (previousRiver)
                {
                    middle = direction.Next();
                }
                else if (nextRiver)
                {
                    middle = direction.Previous();
                }
                else
                {
                    middle = direction;
                }
                if (!cell.HasRoadThroughEdge(middle) && !cell.HasRoadThroughEdge(middle.Previous()) && !cell.HasRoadThroughEdge(middle.Next()))
                {
                    return; // prune orphaned rivers on the inside of a curve
                }
                var offset = HexMetrics.GetSolidEdgeMiddle(middle);
                roadCentre += offset / 4;
                if (direction == middle && cell.HasRoadThroughEdge(direction.Opposite()))
                {
                    Features.AddBridge(roadCentre, centre - offset * (HexMetrics.InnerToOuter * 0.7f));
                }
            }

            var ml = Vector3.Lerp(roadCentre, e.v1, interpolators.x);
            var mr = Vector3.Lerp(roadCentre, e.v5, interpolators.y);

            TriangulateRoad(roadCentre, ml, mr, e, edgeRoad, cell.Index);

            if (previousRiver)
            {
                TriangulateRoadEdge(roadCentre, centre, ml, cell.Index);
            }
            if (nextRiver)
            {
                TriangulateRoadEdge(roadCentre, mr, centre, cell.Index);
            }
        }
Ejemplo n.º 4
0
        private void TriangulateConnection(HexDirection direction, HexCell cell, EdgeVertices e1)
        {
            var neighbour = cell.GetNeighbour(direction);

            if (neighbour == null)
            {
                return; // dont add for edge hexes
            }
            var bridge = HexMetrics.GetBridge(direction);

            bridge.y = neighbour.Position.y - cell.Position.y;
            var e2 = new EdgeVertices(
                e1.v1 + bridge,
                e1.v5 + bridge
                );

            var hasRiver = cell.HasRiverThroughEdge(direction);
            var hasRoad  = cell.HasRoadThroughEdge(direction);

            if (hasRiver)
            {
                var startV3 = e2.v3.y;
                e2.v3.y = neighbour.StreamBedY;
                var indices = new Vector3(cell.Index, neighbour.Index, cell.Index);

                // by definition, both cells have rivers through them
                // however, if both are underwater, then we want (i want) no river bed
                // if only one is, the river should merge with the stream
                // EXCEPT if there is an elevation difference, in which case we need the stream bed to make a waterfall

                // if im a river and the neighbour is a river
                if (!cell.IsUnderwater && !neighbour.IsUnderwater)
                {
                    TriangulateRiverQuad(
                        e1.v2, e1.v4, e2.v2, e2.v4, cell.RiverSurfaceY, neighbour.RiverSurfaceY, 0.8f,
                        cell.HasIncomingRiver && cell.IncomingRiver == direction, indices);
                }
                // if im a river and the neighbour is beneath me
                else if (!cell.IsUnderwater && cell.Elevation > neighbour.WaterLevel)
                {
                    TriangulateWaterfallInWater(
                        e1.v2, e1.v4, e2.v2, e2.v4,
                        cell.RiverSurfaceY, neighbour.RiverSurfaceY,
                        neighbour.WaterLevel, indices);
                }
                // im underwater but the neighbour is heigher than me
                else if (cell.IsUnderwater && !neighbour.IsUnderwater && neighbour.Elevation > cell.WaterLevel)
                {
                    TriangulateWaterfallInWater(
                        e2.v4, e2.v2, e1.v4, e1.v2,
                        neighbour.RiverSurfaceY, cell.RiverSurfaceY,
                        cell.WaterLevel, indices);
                }
                else if ((cell.IsUnderwater == neighbour.IsUnderwater == true) || // both underwater
                         !cell.IsUnderwater && neighbour.IsUnderwater) // river into water on same level
                {
                    e2.v3.y = startV3;                                 // if a river, this will smooth e1 (river side) into e2 (lake/sea bed, which is normal surface)
                }
                // if not a river, then e1 is already sea/lake bed, so e2 will now be approximate same level
            }

            if (HexMetrics.GetEdgeType(cell.Elevation, neighbour.Elevation) == HexEdgeType.Slope)
            {
                TriangulateEdgeTerrace(e1, cell, e2, neighbour, hasRoad);
            }
            else
            {
                TriangulateEdgeStrip(e1, weights1, cell.Index, e2, weights2, neighbour.Index, hasRoad);
            }

            Features.AddWall(e1, cell, e2, neighbour, hasRiver, hasRoad);

            if (direction > HexDirection.E)
            {
                return;
            }
            var nextDirection = direction.Next();
            var nextNeighbour = cell.GetNeighbour(nextDirection);

            if (nextNeighbour == null)
            {
                return;
            }

            var v5 = e1.v5 + HexMetrics.GetBridge(nextDirection);

            v5.y = nextNeighbour.Position.y;

            var minElevation = Mathf.Min(cell.Elevation, neighbour.Elevation, nextNeighbour.Elevation);

            if (minElevation == cell.Elevation)
            {
                TriangulateCorner(e1.v5, cell, e2.v5, neighbour, v5, nextNeighbour);
            }
            else if (minElevation == neighbour.Elevation)
            {
                TriangulateCorner(e2.v5, neighbour, v5, nextNeighbour, e1.v5, cell);
            }
            else
            {
                TriangulateCorner(v5, nextNeighbour, e1.v5, cell, e2.v5, neighbour);
            }
        }