Esempio n. 1
0
    // Create area segments borders
    private void CreateAreaBlockerLines()
    {
        foreach (var edge in VoronoiDiagram.Edges)
        {
            if (!edge.Visible())
            {
                continue;
            }

            int         leftAreaSegmentID  = _siteAreaSegmentMap[edge.LeftSite.Coord];
            int         rightAreaSegmentID = _siteAreaSegmentMap[edge.RightSite.Coord];
            AreaSegment leftAreaSegment    = AreaSegmentGraph.GetNodeData(leftAreaSegmentID);
            AreaSegment rightAreaSegment   = AreaSegmentGraph.GetNodeData(rightAreaSegmentID);

            var leftNeighborhood = AreaSegmentGraph.GetNeighbours(leftAreaSegmentID);

            if (leftAreaSegmentID == rightAreaSegmentID ||
                leftAreaSegment.Type == AreaSegment.EAreaSegmentType.Border ||
                rightAreaSegment.Type == AreaSegment.EAreaSegmentType.Border ||
                !leftNeighborhood.Contains(rightAreaSegmentID) ||
                AreaSegmentGraph.GetEdgeValue(leftAreaSegmentID, rightAreaSegmentID) != (int)AreaSegment.EAreaSegmentEdgeType.NonNavigable)
            {
                continue;
            }

            var p0      = edge.ClippedEnds[LR.LEFT].ToUnityVector2();
            var p1      = edge.ClippedEnds[LR.RIGHT].ToUnityVector2();
            var segment = new[] { p0, p1 };
            AreaBlockerLines.Add(segment);
        }
    }
Esempio n. 2
0
    // Checks if segments are neighbours
    private bool AreNeighbours(IEnumerable <int> areaSegments)
    {
        // Check for null
        if (areaSegments == null || !areaSegments.Any())
        {
            return(false);
        }

        // Check if segments are neighbours
        var found    = new List <int> {
        };
        var frontier = new Queue <int>();

        frontier.Enqueue(areaSegments.ElementAt(0));
        while (found.Count < areaSegments.Count() && frontier.Count > 0)
        {
            var element = frontier.Dequeue();
            if (areaSegments.Contains(element))
            {
                found.Add(element);
                foreach (int neighbour in AreaSegmentGraph.GetNeighbours(element))
                {
                    frontier.Enqueue(neighbour);
                }
            }
        }
        return(found.Count == areaSegments.Count());
    }
Esempio n. 3
0
    // Assign areas to the base graph based on a specific set of rules
    private void CreateAreaGraph(Queue <StoryStructure.AreaSegmentRewrite> rewrites)
    {
        var rewritesCopy = new Queue <StoryStructure.AreaSegmentRewrite>(rewrites);

        while (rewrites.Count > 0)
        {
            var rule = rewrites.Dequeue();
            if (!AreaSegmentGraph.Replace(rule.Pattern, rule.Replace, rule.Correspondences))
            {
                // Try again
                Debug.LogWarning("Failed to generate map with current seed: " + Random.state);
                _voronoiSamples += 10;
                CreateBaseGraph(_lloydIterations);
                CreateAreaGraph(rewritesCopy);
            }
        }

        // Any empty area is marked as border
        foreach (var areaSegment in AreaSegmentGraph.GetAllNodeData())
        {
            if (areaSegment.Type == AreaSegment.EAreaSegmentType.Empty)
            {
                areaSegment.Type = AreaSegment.EAreaSegmentType.Border;
            }
        }
    }
Esempio n. 4
0
    // Get area data graph that contains the given area segments, with the respective center and polygon, and neighborhood information
    public Graph <AreaData> GetAreaDataGraph(IEnumerable <int> areaSegments)
    {
        if (!AreNeighbours(areaSegments))
        {
            return(null);
        }

        // Build polygons and gather roads for each site
        Dictionary <int, Vector2[]>         areaSegmentPolygonMap = new Dictionary <int, Vector2[]>();
        Dictionary <int, List <Vector2[]> > areaSegmentRoadMap    = new Dictionary <int, List <Vector2[]> >();

        foreach (int areaSegment in areaSegments)
        {
            var site = new Vector2f(_areaSegmentCenterMap[areaSegment]);
            areaSegmentPolygonMap.Add(areaSegment, GetSitePolygon(site));
            areaSegmentRoadMap.Add(areaSegment, GetSitePaths(site));
        }

        // Build graph
        Dictionary <int, int> graphMap      = new Dictionary <int, int>();
        Graph <AreaData>      areaDataGraph = new Graph <AreaData>();

        foreach (int areaSegment in areaSegments)
        {
            AreaData data = new AreaData
            {
                Center  = _areaSegmentCenterMap[areaSegment],
                Polygon = areaSegmentPolygonMap[areaSegment],
                Segment = AreaSegmentGraph.GetNodeData(areaSegment),
                Paths   = areaSegmentRoadMap[areaSegment]
            };
            int newID = areaDataGraph.AddNode(data);
            graphMap.Add(areaSegment, newID);
        }
        foreach (int areaSegment in areaSegments)
        {
            foreach (int neighbour in AreaSegmentGraph.GetNeighbours(areaSegment))
            {
                if (areaSegments.Contains(neighbour))
                {
                    areaDataGraph.AddEdge(graphMap[areaSegment], graphMap[neighbour], 0);
                }
            }
        }

        return(areaDataGraph);
    }
Esempio n. 5
0
    // Get closest AreaSegmentGraph ID center to specified pos
    private int GetClosestAreaSegmentID(Vector2 pos)
    {
        float smallestDistance   = float.MaxValue;
        int   closestAreaSegment = 0;

        foreach (var id in AreaSegmentGraph.GetAllNodeIDs())
        {
            Vector2 center          = _areaSegmentCenterMap[id];
            float   currentDistance = (center - pos).sqrMagnitude;
            if (currentDistance < smallestDistance)
            {
                smallestDistance   = currentDistance;
                closestAreaSegment = id;
            }
        }
        return(closestAreaSegment);
    }
Esempio n. 6
0
 // Get closest AreaSegment to specified pos
 private AreaSegment GetClosestAreaSegment(Vector2 pos)
 {
     return(AreaSegmentGraph.GetNodeData(GetClosestAreaSegmentID(pos)));
 }
Esempio n. 7
0
    // Create border blocker polygon
    private void CreateBorderBlockerLines(float borderInlandOffset)
    {
        var segments = new List <KeyValuePair <Edge, Vector2> >();

        foreach (var edge in VoronoiDiagram.Edges)
        {
            //Check if this edge is visible before continuing
            if (!edge.Visible())
            {
                continue;
            }

            int         leftAreaSegmentID  = _siteAreaSegmentMap[edge.RightSite.Coord];
            int         rightAreaSegmentID = _siteAreaSegmentMap[edge.LeftSite.Coord];
            AreaSegment leftAreaSegment    = AreaSegmentGraph.GetNodeData(leftAreaSegmentID);
            AreaSegment rightAreaSegment   = AreaSegmentGraph.GetNodeData(rightAreaSegmentID);

            // Either one or the other must be a border type
            if (leftAreaSegment.Type != rightAreaSegment.Type &&
                (leftAreaSegment.Type == AreaSegment.EAreaSegmentType.Border || rightAreaSegment.Type == AreaSegment.EAreaSegmentType.Border))
            {
                // Add border edge with the biome center to scale inwards later
                segments.Add(new KeyValuePair <Edge, Vector2>(edge,
                                                              leftAreaSegment.Type == AreaSegment.EAreaSegmentType.Border ? edge.LeftSite.Coord.ToUnityVector2() : edge.RightSite.Coord.ToUnityVector2()));
            }
        }

        // Group connected segments
        var edgeGroups = new List <List <KeyValuePair <Edge, Vector2> > >();

        while (segments.Count > 0)
        {
            var edges     = new List <KeyValuePair <Edge, Vector2> >();
            var startEdge = segments[0];
            segments.Remove(startEdge);
            Vertex headPoint = startEdge.Key.RightVertex;
            Vertex tailPoint = startEdge.Key.LeftVertex;
            edges.Add(startEdge);

            // Find a polygon
            var polygonClosed = false;
            while (!polygonClosed && segments.Count > 0)
            {
                for (int i = 0; i < segments.Count; i++)
                {
                    var    currentElement = segments[i];
                    Vertex leftPoint      = currentElement.Key.LeftVertex;
                    Vertex rightPoint     = currentElement.Key.RightVertex;
                    if (leftPoint == headPoint)
                    {
                        edges.Add(currentElement);
                        segments.Remove(currentElement);
                        headPoint = rightPoint;
                    }
                    else if (rightPoint == headPoint)
                    {
                        edges.Add(currentElement);
                        segments.Remove(currentElement);
                        headPoint = leftPoint;
                    }

                    // Polygon has been closed
                    if (headPoint == tailPoint)
                    {
                        polygonClosed = true;
                        break;
                    }
                }
            }
            edgeGroups.Add(edges);
        }

        // Iterate over each polygon found previously
        foreach (var edges in edgeGroups)
        {
            var polygon     = new List <Vector2>();
            var borderLines = edges.Select(pair => pair.Key).ToList().EdgesToSortedLines();
            foreach (var line in borderLines)
            {
                // Offset borders towards biome center
                var left   = line[0];
                var right  = line[1];
                var center = Vector2.zero;
                edges.ForEach(e =>
                {
                    var l = e.Key.ClippedEnds[LR.LEFT].ToUnityVector2();
                    var r = e.Key.ClippedEnds[LR.RIGHT].ToUnityVector2();
                    if ((l == left || l == right) && (r == left || r == right))
                    {
                        center = e.Value;
                    }
                });

                left  += (center - left).normalized * borderInlandOffset;
                right += (center - right).normalized * borderInlandOffset;

                // Offsetting can give duplicated points
                if (!polygon.Contains(left))
                {
                    polygon.Add(left);
                }
                if (!polygon.Contains(right))
                {
                    polygon.Add(right);
                }
            }

            // Create border blocker lines
            BorderBlockerLines.AddRange(polygon.ToArray().PolygonToLines());
        }
    }
Esempio n. 8
0
    // Create path lines
    private void CreatePathLines()
    {
        var mainPath     = new List <Vector2[]>();
        var allSidePaths = new List <Vector2[]>();

        foreach (var graphEdge in AreaSegmentGraph.GetAllEdges())
        {
            int      edgeValue    = AreaSegmentGraph.GetEdgeValue(graphEdge);
            Vector2  leftCenter   = _areaSegmentCenterMap[graphEdge.x];
            Vector2  rightCenter  = _areaSegmentCenterMap[graphEdge.y];
            Vector2f leftSite     = new Vector2f(leftCenter);
            Vector2f rightSite    = new Vector2f(rightCenter);
            Vector2  edgeCrossing = Vector2.zero;

            // Get the middle point of the crossing voronoi edge -> ensure crossable point
            foreach (var e in VoronoiDiagram.Edges)
            {
                if (!e.Visible())
                {
                    continue;
                }

                if (e.LeftSite.Coord == leftSite && e.RightSite.Coord == rightSite ||
                    e.LeftSite.Coord == rightSite && e.RightSite.Coord == leftSite)
                {
                    edgeCrossing = (e.ClippedEnds[LR.LEFT] + e.ClippedEnds[LR.RIGHT]).ToUnityVector2() / 2f;
                    break;
                }
            }

            // Add path lines
            switch (edgeValue)
            {
            case (int)AreaSegment.EAreaSegmentEdgeType.MainPath:
                mainPath.Add(new[] { leftCenter, edgeCrossing });
                mainPath.Add(new[] { edgeCrossing, rightCenter });
                break;

            case (int)AreaSegment.EAreaSegmentEdgeType.SidePath:
                allSidePaths.Add(new[] { leftCenter, edgeCrossing });
                allSidePaths.Add(new[] { edgeCrossing, rightCenter });
                break;
            }
        }

        // Separate side paths
        var sidePathsList = new List <List <Vector2[]> >();

        while (allSidePaths.Count > 0)
        {
            var sidePath = new List <Vector2[]>();
            sidePath.Add(allSidePaths[0]);
            allSidePaths.Remove(sidePath[0]);

            bool found = true;
            while (found)
            {
                found = false;
                for (int i = 0; i < allSidePaths.Count; i++)
                {
                    var line      = allSidePaths[i];
                    var predicate = new Func <Vector2[], bool>(a => a[0] == line[0] || a[0] == line[1] || a[1] == line[0] || a[1] == line[1]);
                    if (sidePath.Any(predicate))
                    {
                        found = true;
                        sidePath.Add(line);
                        allSidePaths.Remove(line);
                        break;
                    }
                }
            }
            sidePathsList.Add(sidePath);
        }

        MainPathLines = CreateBezierPath(mainPath);
        foreach (var sidePath in sidePathsList)
        {
            SidePathLines.AddRange(CreateBezierPath(sidePath));
        }
    }
Esempio n. 9
0
    // Create a graph containing all connected empty areas
    private void CreateBaseGraph(int lloydIterations)
    {
        // Create uniform random point distribution and Voronoi Diagram
        var centers = new List <Vector2f>();

        for (int i = 0; i < _voronoiSamples; i++)
        {
            var x = Random.Range(0f, MapSize);
            var y = Random.Range(0f, MapSize);
            centers.Add(new Vector2f(x, y));
        }
        VoronoiDiagram = new Voronoi(centers, new Rectf(0, 0, MapSize, MapSize));

        // Apply Lloyd Relaxation
        VoronoiDiagram.LloydRelaxation(lloydIterations);

        // Assign area segments to initial areas
        foreach (var site in VoronoiDiagram.SiteCoords())
        {
            bool isOnBorder = false;
            var  segments   = VoronoiDiagram.VoronoiBoundaryForSite(site);

            foreach (var segment in segments)
            {
                if (!(segment.p0.x <= VoronoiDiagram.PlotBounds.left) &&
                    !(segment.p0.x >= VoronoiDiagram.PlotBounds.right) &&
                    !(segment.p0.y <= VoronoiDiagram.PlotBounds.top) &&
                    !(segment.p0.y >= VoronoiDiagram.PlotBounds.bottom) &&
                    !(segment.p1.x <= VoronoiDiagram.PlotBounds.left) &&
                    !(segment.p1.x >= VoronoiDiagram.PlotBounds.right) &&
                    !(segment.p1.y <= VoronoiDiagram.PlotBounds.top) &&
                    !(segment.p1.y >= VoronoiDiagram.PlotBounds.bottom))
                {
                    continue;
                }

                isOnBorder = true;
                break;
            }

            // Assign areaSegment to site and corresponding area
            var areaSegment = new AreaSegment(isOnBorder ? AreaSegment.EAreaSegmentType.Border : AreaSegment.EAreaSegmentType.Empty);

            var nodeID = AreaSegmentGraph.AddNode(areaSegment);
            _siteAreaSegmentMap.Add(site, nodeID);
            _areaSegmentCenterMap.Add(nodeID, site.ToUnityVector2());
        }

        // Create navigation graph - for each area segment that is not a border, add reachable neighbors
        foreach (var id in _siteAreaSegmentMap)
        {
            var areaSegment = AreaSegmentGraph.GetNodeData(id.Value);
            if (areaSegment.Type == AreaSegment.EAreaSegmentType.Border)
            {
                continue;
            }

            Vector2 center = _areaSegmentCenterMap[id.Value];
            foreach (var neighbor in VoronoiDiagram.NeighborSitesForSite(new Vector2f(center.x, center.y)))
            {
                var neighborSegment = AreaSegmentGraph.GetNodeData(_siteAreaSegmentMap[neighbor]);
                if (neighborSegment.Type != AreaSegment.EAreaSegmentType.Border)
                {
                    AreaSegmentGraph.AddEdge(_siteAreaSegmentMap[neighbor], id.Value, (int)AreaSegment.EAreaSegmentEdgeType.NonNavigable);
                }
            }
        }
    }