public static GameObject GeneratePolygon(List <Vector2> vertices2D, PolygonMapGenerator PMG, float layer) { // Use the triangulator to get indices for creating triangles Triangulator tr = new Triangulator(vertices2D.ToArray()); int[] indices = tr.Triangulate(); // Create the Vector3 vertices Vector3[] vertices = new Vector3[vertices2D.Count]; Vector4[] tangents = new Vector4[vertices2D.Count]; Vector2[] uvs = new Vector2[vertices2D.Count]; for (int i = 0; i < vertices.Length; i++) { vertices[i] = new Vector3(vertices2D[i].x, layer, vertices2D[i].y); if (PMG != null) { uvs[i] = new Vector2(vertices2D[i].x / PMG.GenerationSettings.Width, vertices2D[i].y / PMG.GenerationSettings.Height); } // tangent calc Vector2 beforeVertex = vertices2D[i == 0 ? vertices2D.Count - 1 : i - 1]; Vector2 thisVertex = vertices2D[i]; Vector2 afterVertex = vertices2D[i == vertices2D.Count - 1 ? 0 : i + 1]; Vector2 targetPoint = GeometryFunctions.GetOffsetIntersection(beforeVertex, thisVertex, afterVertex, 1f, 1f, false); Vector2 tangent = targetPoint - thisVertex; /* * float angle = Mathf.Abs(Vector2.Angle((beforeVertex - thisVertex).normalized, (afterVertex - thisVertex).normalized)); * float factor = (180 - angle) * 0.005f; * tangent *= (1 + factor); */ tangents[i] = new Vector4(tangent.x, 0, tangent.y, 0); } // Create the mesh Mesh msh = new Mesh(); msh.vertices = vertices; msh.tangents = tangents; msh.uv = uvs; msh.triangles = indices; msh.RecalculateNormals(); msh.RecalculateBounds(); // Set up game object with mesh; GameObject polygon = new GameObject("Polygon (" + vertices2D.Count + ")"); MeshRenderer renderer = polygon.AddComponent <MeshRenderer>(); Color ranCol = Color.red; // new Color(Random.Range(0f, 0.3f), Random.Range(0.4f, 1f), Random.Range(0.1f, 0.6f)); renderer.material.color = ranCol; MeshFilter filter = polygon.AddComponent(typeof(MeshFilter)) as MeshFilter; filter.mesh = msh; return(polygon); }
private static void CreateWaterTopology(PolygonMapGenerator PMG) { // Water altitude is <= -1 List <GraphPolygon> firstLevelPolygons = PMG.Polygons.Where(x => x.IsWater && x.IsNextToLand()).ToList(); ApplyWaterTopologyLevel(firstLevelPolygons, -1); }
private static void CreateLandTopology(PolygonMapGenerator PMG) { // Land altitude is >= 1 List <GraphPolygon> firstLevelPolygons = PMG.Polygons.Where(x => !x.IsWater && x.IsNextToWater).ToList(); ApplyLandTopologyLevel(firstLevelPolygons, 1); }
private static void TurnEdgePolygonsToWater(PolygonMapGenerator PMG) { foreach (GraphPolygon p in PMG.Polygons.Where(x => (x.IsEdgePolygon || x.AdjacentPolygons.Any(y => y.IsEdgePolygon)))) { TurnPolygonToWater(p); } }
private static void CreateOuterOcean(PolygonMapGenerator PMG) { // Create outer edge nodes GraphNode oc1 = new GraphNode(new Vector2(-OUTER_OCEAN_SIZE, -OUTER_OCEAN_SIZE), PMG); GraphNode oc2 = new GraphNode(new Vector2(PMG.GenerationSettings.Width + OUTER_OCEAN_SIZE, -OUTER_OCEAN_SIZE), PMG); GraphNode oc3 = new GraphNode(new Vector2(PMG.GenerationSettings.Width + OUTER_OCEAN_SIZE, PMG.GenerationSettings.Height + OUTER_OCEAN_SIZE), PMG); GraphNode oc4 = new GraphNode(new Vector2(-OUTER_OCEAN_SIZE, PMG.GenerationSettings.Height + OUTER_OCEAN_SIZE), PMG); // Add nodes to the generator PMG.AddNode(oc1); PMG.AddNode(oc2); PMG.AddNode(oc3); PMG.AddNode(oc4); // Adding new water polygons PMG.AddPolygon(new List <GraphNode>() { PMG.CornerNodes[0], oc1, oc2, PMG.CornerNodes[1] }, new List <GraphConnection>(), outerPolygon: true); PMG.AddPolygon(new List <GraphNode>() { PMG.CornerNodes[1], oc2, oc3, PMG.CornerNodes[2] }, new List <GraphConnection>(), outerPolygon: true); PMG.AddPolygon(new List <GraphNode>() { PMG.CornerNodes[2], oc3, oc4, PMG.CornerNodes[3] }, new List <GraphConnection>(), outerPolygon: true); PMG.AddPolygon(new List <GraphNode>() { PMG.CornerNodes[3], oc4, oc1, PMG.CornerNodes[0] }, new List <GraphConnection>(), outerPolygon: true); }
public static void CreateBiomes(PolygonMapGenerator PMG) { GenerateTemperature(PMG); GeneratePrecipitation(PMG); foreach (GraphPolygon polygon in PMG.Polygons) { polygon.Biome = GetBiome(polygon); } }
public static void ExpandOceans(PolygonMapGenerator PMG) { int numExpansions = (int)(PMG.Polygons.Count * EXPAND_OCEAN_PERC); Debug.Log("Expanding " + numExpansions + "x the ocean."); for (int i = 0; i < numExpansions; i++) { DoExpandOcean(PMG); } }
/// <summary> /// Turns polygons that are bigger than the max allowed area into water /// </summary> private static void TurnBigPolygonsToWater(PolygonMapGenerator PMG) { foreach (GraphPolygon polygon in PMG.Polygons) { if (polygon.Area > PMG.GenerationSettings.MaxPolygonArea) { TurnPolygonToWater(polygon); } } }
private static void TurnRandomPolygonsToWater(PolygonMapGenerator PMG) { int numWaters = (int)(PMG.Polygons.Count * RANDOM_OCEAN_PERC); Debug.Log("Creating " + numWaters + " random waters."); for (int i = 0; i < numWaters; i++) { DoTurnRandomPolygonToWater(PMG); } }
public static void CreateRivers(PolygonMapGenerator PMG) { int sizePerRiver = UnityEngine.Random.Range(SIZE_PER_RIVER - SIZE_PER_RIVER_RANGE, SIZE_PER_RIVER + SIZE_PER_RIVER_RANGE); int numRivers = PMG.GenerationSettings.Area / sizePerRiver; Debug.Log("Creating " + numRivers + " rivers."); for (int i = 0; i < numRivers; i++) { DoCreateRiver(PMG); } }
private static void CreateBallOceans(PolygonMapGenerator PMG) { int sizePerBallOcean = UnityEngine.Random.Range(SIZE_PER_BALL_OCEAN - SIZE_PER_BALL_OCEAN_RANGE, SIZE_PER_BALL_OCEAN + SIZE_PER_BALL_OCEAN_RANGE); int numBallOceans = Math.Max(PMG.GenerationSettings.Area / sizePerBallOcean, MIN_BALL_OCEANS); Debug.Log("Creating " + numBallOceans + " round oceans."); for (int i = 0; i < numBallOceans; i++) { DoCreateBallOcean(PMG); } }
private static void PerformContinentCuts(PolygonMapGenerator PMG) { int sizePerContinentCuts = UnityEngine.Random.Range(SIZE_PER_CONTINENT_CUT - SIZE_PER_CONTINENT_CUT_RANGE, SIZE_PER_CONTINENT_CUT + SIZE_PER_CONTINENT_CUT_RANGE); int numContinentCuts = Math.Max(PMG.GenerationSettings.Area / sizePerContinentCuts, MIN_CONTINENT_CUTS); Debug.Log("Performing " + numContinentCuts + " continent cuts."); for (int i = 0; i < numContinentCuts; i++) { DoCreateContinentCut(PMG); } }
public static void DoTurnRandomPolygonToWater(PolygonMapGenerator PMG) { List <GraphPolygon> landPolygons = PMG.Polygons.Where(x => !x.IsWater).ToList(); if (landPolygons.Count == 0) { return; } GraphPolygon newWater = landPolygons[UnityEngine.Random.Range(0, landPolygons.Count)]; TurnPolygonToWater(newWater); }
public static void ExpandLand(PolygonMapGenerator PMG) { int targetAmount = (int)(PMG.Polygons.Count * MIN_TOTAL_LAND_COVERAGE); int landPolygons = PMG.Polygons.Where(x => !x.IsWater).Count(); int numExpansions = targetAmount - landPolygons; Debug.Log("Expanding " + numExpansions + "x the land."); for (int i = 0; i < numExpansions; i++) { DoExpandLand(PMG); } }
public static void DoExpandOcean(PolygonMapGenerator PMG) { List <GraphPolygon> shorePolygons = PMG.Polygons.Where(x => !x.IsWater && x.IsNextToWater).ToList(); if (shorePolygons.Count == 0) { return; } GraphPolygon newWater = shorePolygons[UnityEngine.Random.Range(0, shorePolygons.Count)]; TurnPolygonToWater(newWater); }
private static void CreateContinentsWithNoise(PolygonMapGenerator PMG) { ContinentNoise noise = new ContinentNoise((1f / PMG.GenerationSettings.ContinentSizeScaleFactor) * (100f / PMG.GenerationSettings.Area)); foreach (GraphPolygon polygon in PMG.Polygons.Where(x => (!x.IsEdgePolygon && !x.AdjacentPolygons.Any(y => y.IsEdgePolygon)))) { float noiseValue = noise.GetValue(polygon.CenterPoi.x, polygon.CenterPoi.y, PMG.GenerationSettings); if (noiseValue < 0.2f) { TurnPolygonToWater(polygon); } } }
private static void GeneratePrecipitation(PolygonMapGenerator PMG) { int polePrecipitation = 0; int equatorPrecipitation = 5000; PrecipitationNoise noise = new PrecipitationNoise(polePrecipitation, equatorPrecipitation); foreach (GraphPolygon polygon in PMG.Polygons) { float noiseValue = noise.GetValue(polygon.CenterPoi.x, polygon.CenterPoi.y, PMG.GenerationSettings); polygon.Precipitation = (int)noiseValue; } //if (Visualize) NoiseTester.DisplayNoise(noise, NoiseTester.PrecipitationPlane, MapData, polePrecipitation, equatorPrecipitation); }
public static void DoExpandLand(PolygonMapGenerator PMG) { List <GraphPolygon> waterShorePolygons = PMG.Polygons.Where(x => !x.IsEdgePolygon && !x.AdjacentPolygons.Any(y => y.IsEdgePolygon) && x.IsWater && x.IsNextToLand()).ToList(); // When there is no land yet, just convert a random polygon to land if (waterShorePolygons.Count == 0) { waterShorePolygons = PMG.Polygons.Where(x => !x.IsEdgePolygon).ToList(); } GraphPolygon newLand = waterShorePolygons[UnityEngine.Random.Range(0, waterShorePolygons.Count)]; TurnPolygonToLand(newLand); }
private static void GenerateTemperature(PolygonMapGenerator PMG) { float poleTemperature = -12f; float equatorTemperature = 35f; float temperatureModifyRange = 15f; TemperatureNoise noise = new TemperatureNoise(poleTemperature, equatorTemperature, temperatureModifyRange); foreach (GraphPolygon polygon in PMG.Polygons) { float noiseValue = noise.GetValue(polygon.CenterPoi.x, polygon.CenterPoi.y, PMG.GenerationSettings); polygon.Temperature = (int)noiseValue; } //if (Visualize) NoiseTester.DisplayNoise(noise, NoiseTester.TemperaturePlane, MapData, poleTemperature - temperatureModifyRange, equatorTemperature + temperatureModifyRange); }
private static void IdentifyWaterBodies(PolygonMapGenerator PMG) { PMG.WaterBodies = new List <List <GraphPolygon> >(); List <GraphPolygon> polygonsWithoutWaterBody = new List <GraphPolygon>(); polygonsWithoutWaterBody.AddRange(PMG.Polygons.Where(x => x.IsWater && !x.IsOuterPolygon)); while (polygonsWithoutWaterBody.Count > 0) { List <GraphPolygon> waterBodyPolygons = new List <GraphPolygon>(); Queue <GraphPolygon> polygonsToAdd = new Queue <GraphPolygon>(); polygonsToAdd.Enqueue(polygonsWithoutWaterBody[0]); while (polygonsToAdd.Count > 0) { GraphPolygon polygonToAdd = polygonsToAdd.Dequeue(); waterBodyPolygons.Add(polygonToAdd); foreach (GraphPolygon neighbourPolygon in polygonToAdd.AdjacentPolygons.Where(x => x.IsWater && !x.IsOuterPolygon)) { if (!waterBodyPolygons.Contains(neighbourPolygon) && !polygonsToAdd.Contains(neighbourPolygon)) { polygonsToAdd.Enqueue(neighbourPolygon); } } } bool isLake = waterBodyPolygons.Count < 5; PMG.WaterBodies.Add(waterBodyPolygons); // Add outer ocean to ocean if (!isLake) { foreach (GraphPolygon poly in PMG.Polygons.Where(x => x.IsOuterPolygon)) { waterBodyPolygons.Add(poly); } } foreach (GraphPolygon poly in waterBodyPolygons) { polygonsWithoutWaterBody.Remove(poly); } } }
public static void CreateWaters(PolygonMapGenerator PMG) { switch (PMG.GenerationSettings.MapType) { case MapType.Regional: PerformContinentCuts(PMG); TurnRandomPolygonsToWater(PMG); ExpandOceans(PMG); CreateBallOceans(PMG); ExpandLand(PMG); break; case MapType.Island: CreateOuterOcean(PMG); TurnEdgePolygonsToWater(PMG); PerformContinentCuts(PMG); TurnRandomPolygonsToWater(PMG); ExpandOceans(PMG); CreateBallOceans(PMG); ExpandLand(PMG); break; case MapType.FractalNoise: CreateOuterOcean(PMG); TurnEdgePolygonsToWater(PMG); CreateContinentsWithNoise(PMG); break; case MapType.BigOceans: CreateOuterOcean(PMG); TurnEdgePolygonsToWater(PMG); TurnBigPolygonsToWater(PMG); break; } IdentifyLandmasses(PMG); IdentifyWaterBodies(PMG); foreach (GraphPolygon p in PMG.Polygons) { p.UpdateNeighbours(); } }
private static void IdentifyLandmasses(PolygonMapGenerator PMG) { // Identify landmasses PMG.Landmasses = new List <List <GraphPolygon> >(); List <GraphPolygon> polygonsWithoutLandmass = new List <GraphPolygon>(); polygonsWithoutLandmass.AddRange(PMG.Polygons.Where(x => !x.IsWater)); while (polygonsWithoutLandmass.Count > 0) { List <GraphPolygon> landmassPolygons = new List <GraphPolygon>(); Queue <GraphPolygon> polygonsToAdd = new Queue <GraphPolygon>(); polygonsToAdd.Enqueue(polygonsWithoutLandmass[0]); while (polygonsToAdd.Count > 0) { GraphPolygon polygonToAdd = polygonsToAdd.Dequeue(); landmassPolygons.Add(polygonToAdd); foreach (GraphPolygon neighbourPolygon in polygonToAdd.AdjacentPolygons.Where(x => !x.IsWater)) { if (!landmassPolygons.Contains(neighbourPolygon) && !polygonsToAdd.Contains(neighbourPolygon)) { polygonsToAdd.Enqueue(neighbourPolygon); } } } PMG.Landmasses.Add(landmassPolygons); foreach (GraphPolygon poly in landmassPolygons) { polygonsWithoutLandmass.Remove(poly); } } foreach (List <GraphPolygon> landmass in PMG.Landmasses) { foreach (GraphPolygon polygon in landmass) { polygon.Landmass = landmass; } } }
public static Texture2D CreateRegionBorderMaskTexture(PolygonMapGenerator PMG) { int texWidth = PMG.GenerationSettings.Width * 400; int texHeight = PMG.GenerationSettings.Height * 400; Texture2D regionBorderTexture = new Texture2D(texWidth, texHeight); for (int y = 0; y < texHeight; y++) { for (int x = 0; x < texWidth; x++) { regionBorderTexture.SetPixel(x, y, Color.black); } } foreach (GraphConnection c in PMG.InGraphConnections.Where(x => x.Type != BorderType.Water && !(x.StartNode.Type == BorderPointType.Edge && x.EndNode.Type == BorderPointType.Edge))) { int steps = 20; int range = 1; if (c.Type == BorderType.Shore) { range *= 2; } for (int i = 0; i < steps + 1; i++) { Vector2 worldPosition = Vector2.Lerp(c.StartNode.Vertex, c.EndNode.Vertex, 1f * i / steps); int texX = (int)((worldPosition.x / PMG.GenerationSettings.Width) * texWidth); int texY = (int)((worldPosition.y / PMG.GenerationSettings.Height) * texHeight); for (int x = texX - range; x < texX + range + 1; x++) { for (int y = texY - range; y < texY + range + 1; y++) { regionBorderTexture.SetPixel(x, y, Color.white); } } } } regionBorderTexture.Apply(); return(regionBorderTexture); }
public static Texture2D CreateRiverMaskTexture(PolygonMapGenerator PMG) { int texWidth = PMG.GenerationSettings.Width * 400; int texHeight = PMG.GenerationSettings.Height * 400; Texture2D riverMaskTexture = new Texture2D(texWidth, texHeight); for (int y = 0; y < texHeight; y++) { for (int x = 0; x < texWidth; x++) { riverMaskTexture.SetPixel(x, y, Color.black); } } foreach (GraphConnection c in PMG.InGraphConnections.Where(x => x.River != null)) { int steps = 10; int range = (int)c.RiverWidth; for (int i = 0; i < steps + 1; i++) { Vector2 worldPosition = Vector2.Lerp(c.StartNode.Vertex, c.EndNode.Vertex, 1f * i / steps); int texX = (int)((worldPosition.x / PMG.GenerationSettings.Width) * texWidth); int texY = (int)((worldPosition.y / PMG.GenerationSettings.Height) * texHeight); for (int x = texX - range; x < texX + range + 1; x++) { for (int y = texY - range; y < texY + range + 1; y++) { riverMaskTexture.SetPixel(x, y, Color.white); } } } } riverMaskTexture.Apply(); return(riverMaskTexture); }
public static string GetMapHash(PolygonMapGenerator PMG) { StringBuilder hash = new StringBuilder(); // Line 0 (GenerationSettings.*): seed;width;height;minPolygonArea;maxPolygonArea;minContinentSize;maxContinentSize;mapType;continentSizeScale MapGenerationSettings mgs = PMG.GenerationSettings; hash.AppendLine(mgs.Seed + ";" + mgs.Width + ";" + mgs.Height + ";" + mgs.MinPolygonArea + ";" + mgs.MaxPolygonArea + ";" + mgs.MinContinentSize + ";" + mgs.MaxContinentSize + ";" + (int)mgs.MapType + ";" + mgs.ContinentSizeScaleFactor); // Line 1: n_nodes;n_ingraphconnections;n_egdeconnections;n_polygons;n_paths;n_landmasses;n_waterbodies;n_continents hash.AppendLine(PMG.Nodes.Count + ";" + PMG.InGraphConnections.Count + ";" + PMG.EdgeConnections.Count + ";" + PMG.Polygons.Count + ";" + PMG.RiverPaths.Count + ";" + PMG.Landmasses.Count + ";" + PMG.WaterBodies.Count + ";" + PMG.Continents.Count); // Node Lines: id;positionX;positionY;riverWidth;distanceFromNearestOcean foreach (GraphNode n in PMG.Nodes) { hash.AppendLine(n.Id + ";" + n.Vertex.x + ";" + n.Vertex.y + ";" + n.RiverWidth + ";" + n.DistanceFromNearestOcean); } // InGraphConnection Lines: id;fromNodeId;toNodeId;riverWidth foreach (GraphConnection c in PMG.InGraphConnections) { hash.AppendLine(c.Id + ";" + c.StartNode.Id + ";" + c.EndNode.Id + ";" + c.RiverWidth); } // EdgeConnection Lines: id;fromNodeId;toNodeId;riverWidth foreach (GraphConnection c in PMG.EdgeConnections) { hash.AppendLine(c.Id + ";" + c.StartNode.Id + ";" + c.EndNode.Id + ";" + c.RiverWidth); } // Polygon Lines: id;[nodeIds];[connectionIds] foreach (GraphPolygon p in PMG.Polygons) { hash.Append(p.Id + ";"); foreach (GraphNode n in p.Nodes) { hash.Append(n.Id + ","); } hash.Append(";"); foreach (GraphConnection c in p.Connections) { hash.Append(c.Id + ","); } hash.AppendLine(); } // River Path Lines: id;[nodeIds];[connectionIds];[polygonIds] foreach (GraphPath r in PMG.RiverPaths) { hash.Append(r.Id + ";"); foreach (GraphNode n in r.Nodes) { hash.Append(n.Id + ","); } hash.Append(";"); foreach (GraphConnection c in r.Connections) { hash.Append(c.Id + ","); } hash.Append(";"); foreach (GraphPolygon p in r.Polygons) { hash.Append(p.Id + ","); } hash.AppendLine(); } // Landmass Lines: [polygonIds] foreach (List <GraphPolygon> list in PMG.Landmasses) { foreach (GraphPolygon p in list) { hash.Append("p.Id" + ","); } hash.AppendLine(); } // Water Body Lines: [polygonIds] foreach (List <GraphPolygon> list in PMG.WaterBodies) { foreach (GraphPolygon p in list) { hash.Append("p.Id" + ","); } hash.AppendLine(); } // Continent Lines: [polygonIds] foreach (List <GraphPolygon> list in PMG.Continents) { foreach (GraphPolygon p in list) { hash.Append("p.Id" + ","); } hash.AppendLine(); } return(hash.ToString()); }
public static Map LoadMapFromHash(PolygonMapGenerator PMG, string mapHash) { string[] lines = mapHash.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); int lineIndex = 0; // Line 0: MapGenerationSettings: seed;width;height;minPolygonArea;maxPolygonArea;minContinentSize;maxContinentSize;mapType;continentSizeScale int debugI = 0; Debug.Log(debugI++); string[] mgsLine = lines[lineIndex++].Split(';'); int seed = int.Parse(mgsLine[0]); int width = int.Parse(mgsLine[1]); int height = int.Parse(mgsLine[2]); float minPolygonArea = float.Parse(mgsLine[3]); float maxPolygonArea = float.Parse(mgsLine[4]); int minContinentSize = int.Parse(mgsLine[5]); int maxContinentSize = int.Parse(mgsLine[6]); MapType mapType = (MapType)int.Parse(mgsLine[7]); float continentSizeScale = float.Parse(mgsLine[8]); PMG.GenerationSettings = new MapGenerationSettings(seed, width, height, minPolygonArea, maxPolygonArea, minContinentSize, maxContinentSize, mapType, continentSizeScale); Debug.Log(debugI++); // Line 1: n_nodes;n_ingraphconnections;n_egdeconnections;n_polygons;n_paths;n_landmasses;n_waterbodies;n_continents string[] line1 = lines[lineIndex++].Split(';'); int n_nodes = int.Parse(line1[0]); int n_inGraphConnections = int.Parse(line1[1]); int n_edgeConnections = int.Parse(line1[2]); int n_polygons = int.Parse(line1[3]); int n_riverPaths = int.Parse(line1[4]); int n_landmasses = int.Parse(line1[5]); int n_waterBodies = int.Parse(line1[6]); int n_continents = int.Parse(line1[7]); Debug.Log(debugI++); // Node Lines: id;positionX;positionY;riverWidth;distanceFromNearestOcean PMG.Nodes.Clear(); Dictionary <int, GraphNode> nodeMap = new Dictionary <int, GraphNode>(); for (int i = 0; i < n_nodes; i++) { string[] attributes = lines[lineIndex++].Split(';'); int id = int.Parse(attributes[0]); float x = float.Parse(attributes[1]); float y = float.Parse(attributes[2]); float riverWidth = float.Parse(attributes[3]); int distanceFromNearestOcean = int.Parse(attributes[4]); GraphNode node = new GraphNode(id, x, y, riverWidth, distanceFromNearestOcean); nodeMap.Add(id, node); PMG.Nodes.Add(node); } Debug.Log(debugI++); // InGraphConnection Lines: id;fromNodeId;toNodeId;riverWidth PMG.InGraphConnections.Clear(); Dictionary <int, GraphConnection> connectionMap = new Dictionary <int, GraphConnection>(); for (int i = 0; i < n_inGraphConnections; i++) { string[] attributes = lines[lineIndex++].Split(';'); int id = int.Parse(attributes[0]); int startNodeId = int.Parse(attributes[1]); int endNodeId = int.Parse(attributes[2]); float riverWidth = float.Parse(attributes[3]); GraphConnection connection = new GraphConnection(id, nodeMap[startNodeId], nodeMap[endNodeId], riverWidth); connectionMap.Add(id, connection); PMG.InGraphConnections.Add(connection); } Debug.Log(debugI++); // EdgeConnection Lines: id;fromNodeId;toNodeId;riverWidth PMG.EdgeConnections.Clear(); for (int i = 0; i < n_edgeConnections; i++) { string[] attributes = lines[lineIndex++].Split(';'); int id = int.Parse(attributes[0]); int startNodeId = int.Parse(attributes[1]); int endNodeId = int.Parse(attributes[2]); float riverWidth = float.Parse(attributes[3]); GraphConnection connection = new GraphConnection(id, nodeMap[startNodeId], nodeMap[endNodeId], riverWidth); connectionMap.Add(id, connection); PMG.EdgeConnections.Add(connection); } Debug.Log(debugI++); // Polygon Lines: id;[nodeIds];[connectionIds] PMG.Polygons.Clear(); Dictionary <int, GraphPolygon> polygonMap = new Dictionary <int, GraphPolygon>(); for (int i = 0; i < n_polygons; i++) { string[] attributes = lines[lineIndex++].Split(';'); int id = int.Parse(attributes[0]); List <GraphNode> nodes = new List <GraphNode>(); string[] nodeIds = attributes[1].Split(','); foreach (string s in nodeIds) { nodes.Add(nodeMap[int.Parse(s)]); } List <GraphConnection> connections = new List <GraphConnection>(); string[] connectionIds = attributes[2].Split(','); foreach (string s in connectionIds) { connections.Add(connectionMap[int.Parse(s)]); } GraphPolygon polygon = new GraphPolygon(id, nodes, connections); polygonMap.Add(id, polygon); PMG.Polygons.Add(polygon); } Debug.Log(debugI++); // River Path Lines: id;[nodeIds];[connectionIds];[polygonIds] PMG.RiverPaths.Clear(); for (int i = 0; i < n_riverPaths; i++) { string[] attributes = lines[lineIndex++].Split(';'); int id = int.Parse(attributes[0]); List <GraphNode> nodes = new List <GraphNode>(); string[] nodeIds = attributes[1].Split(','); foreach (string s in nodeIds) { nodes.Add(nodeMap[int.Parse(s)]); } List <GraphConnection> connections = new List <GraphConnection>(); string[] connectionIds = attributes[2].Split(','); foreach (string s in connectionIds) { connections.Add(connectionMap[int.Parse(s)]); } List <GraphPolygon> polygons = new List <GraphPolygon>(); string[] polygonIds = attributes[3].Split(','); foreach (string s in polygonIds) { polygons.Add(polygonMap[int.Parse(s)]); } GraphPath path = new GraphPath(id, nodes, connections, polygons); PMG.RiverPaths.Add(path); } Debug.Log(debugI++); // Landmass Lines: [polygonIds] PMG.Landmasses.Clear(); for (int i = 0; i < n_landmasses; i++) { string[] attributes = lines[lineIndex++].Split(';'); List <GraphPolygon> polygons = new List <GraphPolygon>(); string[] polygonIds = attributes[0].Split(','); foreach (string s in polygonIds) { polygons.Add(polygonMap[int.Parse(s)]); } PMG.Landmasses.Add(polygons); } Debug.Log(debugI++); // WaterBody Lines: [polygonIds] PMG.WaterBodies.Clear(); for (int i = 0; i < n_waterBodies; i++) { string[] attributes = lines[lineIndex++].Split(';'); List <GraphPolygon> polygons = new List <GraphPolygon>(); string[] polygonIds = attributes[0].Split(','); foreach (string s in polygonIds) { polygons.Add(polygonMap[int.Parse(s)]); } PMG.WaterBodies.Add(polygons); } Debug.Log(debugI++); // Continent Lines: [polygonIds] PMG.Continents.Clear(); for (int i = 0; i < n_continents; i++) { string[] attributes = lines[lineIndex++].Split(';'); List <GraphPolygon> polygons = new List <GraphPolygon>(); string[] polygonIds = attributes[0].Split(','); foreach (string s in polygonIds) { polygons.Add(polygonMap[int.Parse(s)]); } PMG.Continents.Add(polygons); } return(PMG.DrawMap()); }
private static void FindNodeOceanDistances(PolygonMapGenerator PMG) { List <GraphNode> firstLevelNodes = PMG.Nodes.Where(x => x.Type == BorderPointType.Shore).ToList(); ApplyNodeDepthLevel(firstLevelNodes, 1); }
public static void DoCreateContinentCut(PolygonMapGenerator PMG) { // Define random cut circle int avgMapEdgeSize = (int)(Math.Sqrt(PMG.GenerationSettings.Area)); float minDistanceFromMap = avgMapEdgeSize * 0.1f; float maxDistanceFromMap = avgMapEdgeSize * 0.7f; float cutCircleCenterX = 0, cutCircleCenterY = 0; switch (UnityEngine.Random.Range(0, 4)) { case 0: // Bottom side cutCircleCenterX = UnityEngine.Random.Range(-maxDistanceFromMap, PMG.GenerationSettings.Width + maxDistanceFromMap); cutCircleCenterY = UnityEngine.Random.Range(-maxDistanceFromMap, -minDistanceFromMap); break; case 1: // Right side cutCircleCenterX = UnityEngine.Random.Range(PMG.GenerationSettings.Width + minDistanceFromMap, PMG.GenerationSettings.Width + maxDistanceFromMap); cutCircleCenterY = UnityEngine.Random.Range(-minDistanceFromMap, PMG.GenerationSettings.Height + maxDistanceFromMap); break; case 2: // Top side cutCircleCenterX = UnityEngine.Random.Range(-maxDistanceFromMap, PMG.GenerationSettings.Width + maxDistanceFromMap); cutCircleCenterY = UnityEngine.Random.Range(PMG.GenerationSettings.Height + minDistanceFromMap, PMG.GenerationSettings.Height + maxDistanceFromMap); break; case 3: // Left side cutCircleCenterX = UnityEngine.Random.Range(-maxDistanceFromMap, -minDistanceFromMap); cutCircleCenterY = UnityEngine.Random.Range(-minDistanceFromMap, PMG.GenerationSettings.Height + maxDistanceFromMap); break; } Vector2 cutCircleCenter = new Vector2(cutCircleCenterX, cutCircleCenterY); int cutCircleRadius = avgMapEdgeSize; // Check for each node if it is close to cut circle float distanceMargin = UnityEngine.Random.Range(MIN_CONTINENT_CUT_WIDTH, MAX_CONTINENT_CUT_WIDTH); List <GraphPolygon> newOceanPolygons = new List <GraphPolygon>(); foreach (GraphNode n in PMG.Nodes.Where(x => !x.IsWaterNode())) { float distance = Vector2.Distance(n.Vertex, cutCircleCenter); if (distance >= cutCircleRadius - distanceMargin && distance <= cutCircleRadius + distanceMargin) { foreach (GraphPolygon p in n.Polygons) { if (!newOceanPolygons.Contains(p)) { newOceanPolygons.Add(p); } } } } foreach (GraphPolygon p in newOceanPolygons) { if (UnityEngine.Random.Range(0f, 1f) > CONTINENT_SPLIT_ISLAND_CHANCE) { TurnPolygonToWater(p); } } }
// Start is called before the first frame update public static void CreateTopology(PolygonMapGenerator PMG) { CreateLandTopology(PMG); CreateWaterTopology(PMG); FindNodeOceanDistances(PMG); }
public static void CreateContinents(PolygonMapGenerator PMG) { PMG.Continents = new List<List<GraphPolygon>>(); // 1. Create one continent per landmass foreach (List<GraphPolygon> landmass in PMG.Landmasses) { List<GraphPolygon> continentPolygons = new List<GraphPolygon>(); continentPolygons.AddRange(landmass); foreach (GraphPolygon landmassPoly in landmass) landmassPoly.Continent = continentPolygons; PMG.Continents.Add(continentPolygons); } // 2. Split big landmasses into mutliple continents List<GraphPolygon> biggestContinent = PMG.Continents.OrderByDescending(x => x.Count).First(); while(biggestContinent.Count > PMG.GenerationSettings.MaxContinentSize) { int minCuts = int.MaxValue; int minCutMinRegions = int.MaxValue; KargerGraph bestGraph = null; int cyclesWithoutImprovement = 0; while(cyclesWithoutImprovement < 50 || bestGraph == null) { cyclesWithoutImprovement++; KargerGraph graph = SplitClusterOnce(biggestContinent); if(graph.Vertices[0].ContainedPolygons.Count >= PMG.GenerationSettings.MinContinentSize && graph.Vertices[1].ContainedPolygons.Count >= PMG.GenerationSettings.MinContinentSize) { int graphMinCutMinRegions = Mathf.Min(graph.Vertices[0].ContainedPolygons.Count, graph.Vertices[1].ContainedPolygons.Count); if (graph.CutSize < minCuts || (graph.CutSize == minCuts && graphMinCutMinRegions > minCutMinRegions)) { minCuts = graph.CutSize; minCutMinRegions = graphMinCutMinRegions; bestGraph = graph; cyclesWithoutImprovement = 0; } } } List<GraphPolygon> newContinent = new List<GraphPolygon>(); foreach (GraphPolygon splittedPolygon in bestGraph.Vertices[0].ContainedPolygons) { newContinent.Add(splittedPolygon); biggestContinent.Remove(splittedPolygon); splittedPolygon.Continent = newContinent; } PMG.Continents.Add(newContinent); biggestContinent = PMG.Continents.OrderByDescending(x => x.Count).First(); } // 3. Assign islands that are too small to the nearest continent List<GraphPolygon> smallestContinent = PMG.Continents.OrderBy(x => x.Count).First(); while(smallestContinent.Count < PMG.GenerationSettings.MinContinentSize) { float shortestDistance = float.MaxValue; GraphPolygon shortestDistancePolygon = null; foreach(GraphPolygon continentPoly in smallestContinent) { foreach(GraphPolygon waterNeighbour in continentPoly.WaterNeighbours) { if(!smallestContinent.Contains(waterNeighbour)) { float distance = PolygonMapFunctions.GetPolygonDistance(continentPoly, waterNeighbour); if (distance < shortestDistance) { shortestDistance = distance; shortestDistancePolygon = waterNeighbour; } } } } foreach (GraphPolygon continentPoly in smallestContinent) { continentPoly.Continent = shortestDistancePolygon.Continent; shortestDistancePolygon.Continent.Add(continentPoly); } smallestContinent.Clear(); PMG.Continents.Remove(smallestContinent); smallestContinent = PMG.Continents.OrderBy(x => x.Count).First(); } }