Esempio n. 1
0
 /// <summary>
 /// Used for creating artificial corners, i.e. ones that are forced
 /// instead of created through a DelaunayTriangle.
 /// </summary>
 /// <param name="pos"></param>
 /// <param name="cornerNum"></param>
 public Corner(Vector2 pos, int cornerNum, bool mapCorner = false) : base(pos)
 {
     num         = cornerNum;
     isOOB       = !VoronoiGenerator.IsInMapBounds(position);
     isMapCorner = mapCorner;
     isOnBorder  = isMapCorner;
 }
Esempio n. 2
0
 private void CreateRNG()
 {
     if (newRandomSeed)
     {
         randomSeed = System.DateTime.Now.Ticks.ToString();
     }
     instance = this;
     rng      = new Random(randomSeed.GetHashCode());
 }
Esempio n. 3
0
        /// <summary>
        /// Based off of https://www.redblobgames.com/maps/noisy-edges/
        /// </summary>
        public void CreateNoisyEdge(int subdivisions)
        {
            if (segments != null)             // already noisified this edge
            {
                return;
            }

            if (polygons.Count != 2)
            {             // probably on the map edge
                if (polygons.Count > 2 || polygons.Count == 0)
                {
                    throw new Exception("Invalid polygon count in edge " + id + ". Count: " + polygons.Count);
                }
                CreateSimpleBorder();
                return;
            }

            segments = new List <Vector3>();

            pairedEdge = polygons[0].centroid.GetConnectingEdge(polygons[1].centroid);
            if (pairedEdge == null)
            {
                throw new Exception("Invalid delaunay edge");
            }

            Vector3 control1 = pairedEdge.start.position;
            Vector3 control2 = pairedEdge.end.position;

            if (!VoronoiGenerator.TryGetLineIntersections(
                    control1, control2, start.position, end.position,
                    out Vector2 intersectPoint, out float tMid, out float t2))
            {
                Debug.LogWarning("SPECIAL CASE: voronoi and delaunay edges do not meet");
                CreateSimpleBorder();
                return;
            }

            segments.Add(start.position);
            segments.AddRange(
                CreateSegments(start.position, end.position,
                               control1, control2, subdivisions, -tMid));
            segments.Add(end.position);
        }
Esempio n. 4
0
        private List <Vector3> CreateSegments(
            Vector3 lineStart, Vector3 lineEnd,
            Vector3 control1, Vector3 control2, int subdivisions, float tMid)
        {
            List <Vector3> newSegments = new List <Vector3>();

            if (subdivisions > 0)
            {
                float lineDist    = Vector3.Distance(lineStart, lineEnd);
                float controlDist = Vector3.Distance(control1, control2);
                if (lineDist < controlDist)
                {                 // clamp the control points to stop ugly extreme lines
                    float diff = (controlDist - lineDist) * .5f;

                    Vector3 newControl1 = Vector3.MoveTowards(control1, control2, diff);
                    Vector3 newControl2 = Vector3.MoveTowards(control2, control1, diff);
                    control1 = newControl1;
                    control2 = newControl2;
                }

                Vector3 edgeCenter1 = (lineStart + control1) * .5f;
                Vector3 edgeCenter2 = (lineStart + control2) * .5f;

                Vector3 midPoint = Vector3.Lerp(control1, control2,
                                                VoronoiGenerator.GetNewT(tMid, isRiver));
                newSegments.AddRange(
                    CreateSegments(lineStart, midPoint, edgeCenter1, edgeCenter2, subdivisions - 1, tMid));

                newSegments.Add(midPoint);

                Vector3 edgeCenter3 = (lineEnd + control1) * .5f;
                Vector3 edgeCenter4 = (lineEnd + control2) * .5f;

                newSegments.AddRange(
                    CreateSegments(midPoint, lineEnd, edgeCenter3, edgeCenter4, subdivisions - 1, tMid));
            }

            return(newSegments);
        }
Esempio n. 5
0
        /// <summary>
        /// Some random seeds produce invalid polygon that uses map corners. Ex:
        /// 637427950365396994
        /// 637427958541256155
        /// </summary>
        /// <param name="vGen"></param>
        /// <param name="dGraph"></param>
        public VoronoiGraph(VoronoiGenerator vGen, DelaunayGraph dGraph)
        {
            generator     = vGen;
            delaunayGraph = dGraph;
            cornerCount   = 0;
            uniqueVEdges  = new HashSet <VEdge>();
            uniqueCorners = new HashSet <Corner>();
            removeCorners = new List <Corner>();
            mapCorners    = new Dictionary <byte, Corner>()
            {
                [VoronoiGenerator.TopRightCornerByte]    = new Corner(VoronoiGenerator.topRight, cornerCount++, true),
                [VoronoiGenerator.TopLeftCornerByte]     = new Corner(VoronoiGenerator.topLeft, cornerCount++, true),
                [VoronoiGenerator.BottomRightCornerByte] = new Corner(VoronoiGenerator.bottomRight, cornerCount++, true),
                [VoronoiGenerator.BottomLeftCornerByte]  = new Corner(VoronoiGenerator.bottomLeft, cornerCount++, true),
            };

            invalidatedPolygons = new List <Polygon>();
            invalidatedEdges    = new HashSet <VEdge>();

            polygons = new List <Polygon>();
            for (int i = 0; i < dGraph.centroids.Count; ++i)             // first 4 centroids are map corners
            {
                Polygon poly = new Polygon(dGraph.centroids[i]);
                polygons.Add(poly);
            }

            if (polygons[0].corners == null || polygons[1].corners == null ||
                polygons[2].corners == null || polygons[3].corners == null)
            {
                logMsgs = new List <string>();

                logMsgs.Add("****** Error found on Seed: " + generator.randomSeed + "******");
                logMsgs.Add("Map dimensions: " + generator.mapWidth + ", " + generator.mapHeight);
                logMsgs.Add("Region amt: " + generator.regionAmount);
                logMsgs.Add("MinSqrDistBtwnSites: " + generator.minSqrDistBtwnSites);
                logMsgs.Add("MinDistBtwnSiteAndBorder: " + generator.minDistBtwnSiteAndBorder);
                logMsgs.Add("MinDistBtwnCornerAndBorder: " + generator.minDistBtwnCornerAndBorder);
                logMsgs.Add("MinEdgeLengthToMerge: " + generator.minEdgeLengthToMerge);
                logMsgs.Add("Merge near corners: " + generator.mergeNearCorners);
                logMsgs.Add("******************************************\n");
                logMsgs.Add("Corner polygon did not make it passed initial generation");
                System.IO.File.WriteAllLines(logFilePath + "BorderCornerDeletedIssue_" + generator.randomSeed + ".txt", logMsgs);
                Log("Corner polygon did not make it passed initial generation", LogType.Exception, false);
            }
            VoronoiHelper.Associate(polygons[0], mapCorners[TopLeftCornerByte]);
            VoronoiHelper.Associate(polygons[1], mapCorners[TopRightCornerByte]);
            VoronoiHelper.Associate(polygons[2], mapCorners[BottomRightCornerByte]);
            VoronoiHelper.Associate(polygons[3], mapCorners[BottomLeftCornerByte]);

            if (VoronoiGenerator.MergeNearCorners)
            {
                MergeNearCorners();
            }

            if (generator.clampToMapBounds)
            {
                if (!ClampToMapBounds())
                {
                    return;
                }

                foreach (Corner corner in uniqueCorners)
                {
                    if (corner.isInvalidated)
                    {
                        if (!removeCorners.Contains(corner))
                        {
                            removeCorners.Add(corner);
                        }
                        continue;
                    }

                    if (corner.isOOB)
                    {
                        removeCorners.Add(corner);
                    }
                }
            }


            for (int i = removeCorners.Count - 1; i >= 0; --i)
            {
                Corner removingCorner = removeCorners[i];
                for (int j = removingCorner.connectedEdges.Count - 1; j >= 0; --j)
                {
                    VEdge edge = removingCorner.connectedEdges[j];
                    removingCorner.connectedEdges.Remove(edge);
                    uniqueVEdges.Remove(edge);
                    Corner opposite = edge.GetOppositeSite(removingCorner);
                    opposite.connectedEdges.Remove(edge);
                    foreach (var poly in removingCorner.polygons)
                    {
                        poly.Remove(edge);
                    }
                }

                removingCorner.connectedEdges.Clear();
                RemoveCorner(removingCorner);
            }


            int culled = 0;

            foreach (var polygon in invalidatedPolygons)
            {
                debugPolygons.Add(polygon);
                polygons.Remove(polygon);
                ++culled;
            }


            foreach (Polygon polygon in polygons)
            {
                polygon.CenterCentroid();
                polygon.SortEdges();
            }
        }
Esempio n. 6
0
        public void GenerateMap()
        {
            instance = this;
            DestroyImmediate(lr);
            ClearMap();

            CreateRNG();

            MergeNearCorners = mergeNearCorners;

            minSqrDistBetweenCorners = minSqrDistBtwnSites;
            minDistCornerAndBorder   = minDistBtwnCornerAndBorder;



            mapBounds = new Rect(0, 0, mapWidth, mapHeight);

            topLeft     = new Vector2(mapBounds.xMin, mapBounds.yMax);
            topRight    = new Vector2(mapBounds.xMax, mapBounds.yMax);
            bottomRight = new Vector2(mapBounds.xMax, mapBounds.yMin);
            bottomLeft  = new Vector2(mapBounds.xMin, mapBounds.yMin);

            borderEndPoints = new Dictionary <MapSide, Tuple <Vector2, Vector2> >();
            borderEndPoints.Add(MapSide.Top, new Tuple <Vector2, Vector2>(topLeft, topRight));
            borderEndPoints.Add(MapSide.Right, new Tuple <Vector2, Vector2>(topRight, bottomRight));
            borderEndPoints.Add(MapSide.Bottom, new Tuple <Vector2, Vector2>(bottomRight, bottomLeft));
            borderEndPoints.Add(MapSide.Left, new Tuple <Vector2, Vector2>(bottomLeft, topLeft));

            List <Vector2> sites = new List <Vector2>();

            // create corner sites

            sites.Add(topLeft);
            sites.Add(topRight);
            sites.Add(bottomRight);
            sites.Add(bottomLeft);

            int retryAttempts = 0;

            for (int i = 0; i < regionAmount; i++)
            {
                Vector2 site = new Vector2(
                    (float)(minDistBtwnSiteAndBorder + rng.NextDouble() * (mapHeight - minDistBtwnSiteAndBorder * 2)),
                    (float)(minDistBtwnSiteAndBorder + rng.NextDouble() * (mapWidth - minDistBtwnSiteAndBorder * 2)));
                if (IsTooNear(sites, site))
                {                   // try again
                    ++retryAttempts;
                    if (retryAttempts > 25)
                    {
                        Debug.Log("Unable to place new site within exceptable distance parameters."
                                  + "\nAborting creating new sites. Created " + i + " out of " + regionAmount);
                        break;
                    }

                    --i;
                }
                else
                {
                    sites.Add(site);
                }
            }

            try
            {
                dGraph = new DelaunayGraph(sites);
                vGraph = new VoronoiGraph(this, dGraph);
                CreateRegions();
            }
            catch (System.Exception ex)
            {
                newRandomSeed = false;                 // make sure we stay on this seed until the problem has been rectified
                Debug.LogException(ex);
            }
        }
Esempio n. 7
0
 public Corner(DelaunayTriangle triangle, int cornerNum) : base(triangle.realCenter)
 {
     this.delaunayTriangle = triangle;
     num   = cornerNum;
     isOOB = !VoronoiGenerator.IsInMapBounds(position);
 }