private void CollectRiver(Corner c, RiverBranch riverBranch) { foreach (var edge in c.Edges) { if (edge.WaterFlow > 1) { if (!_rivers.Contains(edge)) { var newBranch = new RiverBranch { Edge = edge, ParentBranch = riverBranch }; riverBranch.Branches.Add(newBranch); _rivers.Add(edge); CollectRiver(edge.GetOpposite(c), newBranch); } } } }
private int FillRiver(RiverBranch branch) { int flood; if (branch.Final) { flood = 1; } else { flood = branch.Branches.Sum(b => FillRiver(b)) + 1; } if (branch.Edge != null) { branch.Edge.WaterFlow = flood; } return(flood); }
private void EnumerateTree(RiverBranch branch, Action <RiverBranch> action) { action(branch); branch.Branches.ForEach(b => EnumerateTree(b, action)); }
/// <summary> /// Starts plan generation process /// </summary> public void Generate() { var datapoints = new List <Vector>(Parameters.PolygonsCount); var r = new Random(Parameters.GridSeed); for (int i = 0; i < Parameters.PolygonsCount; i++) { datapoints.Add(new Vector(r.Next(0, Parameters.MapSize.X), r.Next(0, Parameters.MapSize.Y))); } var graph = Fortune.ComputeVoronoiGraph(datapoints); for (int i = 0; i < Parameters.RelaxCount; i++) { Relax(graph, datapoints); graph = Fortune.ComputeVoronoiGraph(datapoints); } FillMap(graph); { // adding elevation data var elevationNoise = new SimplexNoise(new Random(Parameters.ElevationSeed)); elevationNoise.SetParameters(0.0008, SimplexNoise.InflectionMode.NoInflections, SimplexNoise.ResultScale.ZeroToOne); foreach (var poly in this) { var noiseVal = elevationNoise.GetNoise2DValue(poly.Center.X, poly.Center.Y, 4, 0.8); var col = 255 / noiseVal.MaxValue * noiseVal.Value; poly.Elevation = (int)col; } //// elevate each corner //if (!Parameters.CenterElevation) // ElevateCorners(); } if (Parameters.CenterElevation) { var poly = GetAtPoint(new Point(Parameters.MapSize.X / 2, Parameters.MapSize.Y / 2)); poly.Elevation = 200; StartPropagation(poly, 15); } // making island { //r = new Random((int)voronoiSeedNumeric.Value); var borderElevation = 80; var step = 20; for (int x = 0; x < Parameters.MapSize.X; x += 5) { var poly = GetAtPoint(new Point(x, 0)); poly.Elevation = borderElevation;// r.Next(0, 100); StartPropagation(poly, step); poly = GetAtPoint(new Point(x, Parameters.MapSize.Y)); poly.Elevation = borderElevation;// r.Next(0, 100); StartPropagation(poly, step); } for (int y = 0; y < Parameters.MapSize.Y; y += 5) { var poly = GetAtPoint(new Point(0, y)); poly.Elevation = borderElevation;// r.Next(0, 100); StartPropagation(poly, step); poly = GetAtPoint(new Point(Parameters.MapSize.X, y)); poly.Elevation = borderElevation;// r.Next(0, 100); StartPropagation(poly, step); } } ElevateCorners(); #region Moisturizing { var noise = new SimplexNoise(new Random(Parameters.ElevationSeed)); noise.SetParameters(0.0008d, SimplexNoise.InflectionMode.NoInflections, SimplexNoise.ResultScale.ZeroToOne); foreach (var poly in this) { var noiseVal = noise.GetNoise2DValue(poly.Center.X, poly.Center.Y, 2, 0.8); var col = 100 / noiseVal.MaxValue * noiseVal.Value; poly.Moisture = (int)col; foreach (var corner in poly.Corners) { noiseVal = noise.GetNoise2DValue(corner.Point.X, corner.Point.Y, 2, 0.8); col = 2 / noiseVal.MaxValue * noiseVal.Value; corner.WaterFlow = (int)col; } } // fix heights foreach (var poly in this) { foreach (var neighbor in poly.Neighbors) { if (poly.Elevation == neighbor.Elevation) { neighbor.Elevation = (int)neighbor.Neighbors.Average(n => n.Elevation); } } } // calculate rivers _corners1 = new HashSet <Corner>(); // get unique corners foreach (var poly in this) { foreach (var corner in poly.Corners) { if (!_corners1.Contains(corner) && corner.Polygons.Find(p => p.Elevation <= 127) == null) { _corners1.Add(corner); } } } var list = new List <Corner>(_corners1); list.Sort(new CornerHeightComparer()); // propagate flow foreach (var corner in list) { // find lowest edge Edge lowestEdge = corner.Edges[0]; int height = lowestEdge.GetOpposite(corner).Elevation; for (int i = 0; i < corner.Edges.Count; i++) { var tmp = corner.Edges[i].GetOpposite(corner).Elevation; if (tmp < height) { height = tmp; lowestEdge = corner.Edges[i]; } } lowestEdge.WaterFlow += corner.WaterFlow; lowestEdge.GetOpposite(corner).WaterFlow += corner.WaterFlow; } // remove rivers that not going to oceans _waterCorners = new List <Corner>(); foreach (var poly in this) { foreach (var corner in poly.Corners) { int solid = corner.Polygons.Count(p => p.Elevation > 127); if (solid == 2) { _waterCorners.Add(corner); } } } // collect all correct edges _rivers.Clear(); foreach (var waterCorner in _waterCorners) { var root = new RiverBranch(); CollectRiver(waterCorner, root); if (!root.Final) { _riverRoots.Add(root); } } // fix river flows // stage 1: remove all flows foreach (var riverBranch in _riverRoots) { EnumerateTree(riverBranch, b => { if (b.Edge != null) { b.Edge.WaterFlow = 0; } }); } // stage 2: reflow it foreach (var riverBranch in _riverRoots) { FillRiver(riverBranch); } // remove all non-river foreach (var poly in this) { foreach (var edge in poly.Edges) { if (edge.WaterFlow > 0 && !_rivers.Contains(edge)) { edge.WaterFlow = 0; } } } // update moisture for polygons foreach (var poly in this) { if (poly.Elevation > 127) { poly.Moisture = poly.Neighbors.Sum(p => { var v = p.Neighbors.Sum(n => n.Edges.Sum(ed => ed.WaterFlow > 0 ? 1 : 0)); v = v + p.Neighbors.Sum(n => n.Elevation < 127 && !n.Ocean ? 3 : 0); return(p.Edges.Sum(ed => ed.WaterFlow > 0 ? 1 : 0) + v); }); } } } #endregion // detect ocean { SetOcean(GetAtPoint(new Point(0, 0))); SetOcean(GetAtPoint(new Point(Parameters.MapSize.X, 0))); SetOcean(GetAtPoint(new Point(0, Parameters.MapSize.Y))); SetOcean(GetAtPoint(new Point(Parameters.MapSize.X, Parameters.MapSize.Y))); } // set biomes { foreach (var poly in this) { if (poly.Elevation > 127) { poly.Biome = _biome.GetBiomeWith(poly.Elevation, poly.Moisture > _biome.Moisture.Maximum ? _biome.Moisture.Maximum : poly.Moisture); } } } //find coastline foreach (var polygon in this) { foreach (var edge in polygon.Edges) { Polygon poly; Polygon poly2; if (((poly = edge.Polygons.Find(p => p.Elevation > 127)) != null) && ((poly2 = edge.Polygons.Find((p => p.Elevation <= 127))) != null)) { poly.Coast = true; poly2.Coast = true; edge.Coast = true; } } } }