private void DigRiverGroups() { for (int i = 0; i < RiverGroups.Count; i++) { RiverGroup group = RiverGroups[i]; River longest = null; //Find longest river in this group for (int j = 0; j < group.Rivers.Count; j++) { River river = group.Rivers[j]; if (longest == null) { longest = river; } else if (longest.Tiles.Count < river.Tiles.Count) { longest = river; } } if (longest != null) { //Dig out longest path first DigRiver(longest); for (int j = 0; j < group.Rivers.Count; j++) { River river = group.Rivers[j]; if (river != longest) { DigRiver(river, longest); } } } } }
private void FindPathToWater(WorldTile tile, Direction direction, ref River river) { if (tile.TerrainData.Rivers.Contains(river)) { return; } // check if there is already a river on this tile if (tile.TerrainData.Rivers.Count > 0) { river.Intersections++; } river.AddTile(tile); // get neighbors WorldTile left = GetLeft(tile); WorldTile right = GetRight(tile); WorldTile top = GetTop(tile); WorldTile bottom = GetBottom(tile); float leftValue = int.MaxValue; float rightValue = int.MaxValue; float topValue = int.MaxValue; float bottomValue = int.MaxValue; // query height values of neighbors if (left != null && left.GetRiverNeighborCount(river) < 2 && !river.Tiles.Contains(left)) { leftValue = left.TerrainData.HeightValue; } if (right != null && right.GetRiverNeighborCount(river) < 2 && !river.Tiles.Contains(right)) { rightValue = right.TerrainData.HeightValue; } if (top != null && top.GetRiverNeighborCount(river) < 2 && !river.Tiles.Contains(top)) { topValue = top.TerrainData.HeightValue; } if (bottom != null && bottom.GetRiverNeighborCount(river) < 2 && !river.Tiles.Contains(bottom)) { bottomValue = bottom.TerrainData.HeightValue; } // if neighbor is existing river that is not this one, flow into it if (bottom != null && bottom.TerrainData.Rivers.Count == 0 && !bottom.TerrainData.Collidable) { bottomValue = 0; } if (top != null && top.TerrainData.Rivers.Count == 0 && !top.TerrainData.Collidable) { topValue = 0; } if (left != null && left.TerrainData.Rivers.Count == 0 && !left.TerrainData.Collidable) { leftValue = 0; } if (right != null && right.TerrainData.Rivers.Count == 0 && !right.TerrainData.Collidable) { rightValue = 0; } // override flow direction if a tile is significantly lower if (direction == Direction.Left) { if (Math.Abs(rightValue - leftValue) < 0.1f) { rightValue = int.MaxValue; } } if (direction == Direction.Right) { if (Math.Abs(rightValue - leftValue) < 0.1f) { leftValue = int.MaxValue; } } if (direction == Direction.Top) { if (Math.Abs(topValue - bottomValue) < 0.1f) { bottomValue = int.MaxValue; } } if (direction == Direction.Bottom) { if (Math.Abs(topValue - bottomValue) < 0.1f) { topValue = int.MaxValue; } } // find mininum float min = Math.Min(Math.Min(Math.Min(leftValue, rightValue), topValue), bottomValue); // if no minimum found - exit if (min == int.MaxValue) { return; } //Move to next neighbor if (min == leftValue) { if (left != null && left.TerrainData.Collidable) { if (river.CurrentDirection != Direction.Left) { river.TurnCount++; river.CurrentDirection = Direction.Left; } FindPathToWater(left, direction, ref river); } } else if (min == rightValue) { if (right != null && right.TerrainData.Collidable) { if (river.CurrentDirection != Direction.Right) { river.TurnCount++; river.CurrentDirection = Direction.Right; } FindPathToWater(right, direction, ref river); } } else if (min == bottomValue) { if (bottom != null && bottom.TerrainData.Collidable) { if (river.CurrentDirection != Direction.Bottom) { river.TurnCount++; river.CurrentDirection = Direction.Bottom; } FindPathToWater(bottom, direction, ref river); } } else if (min == topValue) { if (top != null && top.TerrainData.Collidable) { if (river.CurrentDirection != Direction.Top) { river.TurnCount++; river.CurrentDirection = Direction.Top; } FindPathToWater(top, direction, ref river); } } }
// Dig river private void DigRiver(River river) { int counter = 0; // How wide are we digging this river? int size = rng.Next(1, 5); //DEF: Try this //int size = 1; river.Length = river.Tiles.Count; // randomize size change int two = river.Length / 2; int three = two / 2; int four = three / 2; int five = four / 2; int twomin = two / 3; int threemin = three / 3; int fourmin = four / 3; int fivemin = five / 3; // randomize lenght of each size int count1 = rng.Next(fivemin, five); if (size < 4) { count1 = 0; } int count2 = count1 + rng.Next(fourmin, four); if (size < 3) { count2 = 0; count1 = 0; } int count3 = count2 + rng.Next(threemin, three); if (size < 2) { count3 = 0; count2 = 0; count1 = 0; } int count4 = count3 + rng.Next(twomin, two); // Make sure we are not digging past the river path if (count4 > river.Length) { int extra = count4 - river.Length; while (extra > 0) { if (count1 > 0) { count1--; count2--; count3--; count4--; extra--; } else if (count2 > 0) { count2--; count3--; count4--; extra--; } else if (count3 > 0) { count3--; count4--; extra--; } else if (count4 > 0) { count4--; extra--; } } } // Dig it out for (int i = river.Tiles.Count - 1; i >= 0; i--) { WorldTile t = river.Tiles[i]; if (counter < count1 && MaxRiverSize > 3) { t.DigRiver(river, 4); } else if (counter < count2 && MaxRiverSize > 2) { t.DigRiver(river, 3); } else if (counter < count3 && MaxRiverSize > 1) { t.DigRiver(river, 2); } else if (counter < count4 && MaxRiverSize > 0) { t.DigRiver(river, 1); } else { t.DigRiver(river, 0); } counter++; } }
// Dig river based on a parent river vein private void DigRiver(River river, River parent) { int intersectionID = 0; int intersectionSize = 0; // determine point of intersection for (int i = 0; i < river.Tiles.Count; i++) { WorldTile t1 = river.Tiles[i]; for (int j = 0; j < parent.Tiles.Count; j++) { WorldTile t2 = parent.Tiles[j]; if (t1 == t2) { intersectionID = i; intersectionSize = t2.TerrainData.RiverSize; } } } int counter = 0; int intersectionCount = river.Tiles.Count - intersectionID; int size = rng.Next(intersectionSize, 5); river.Length = river.Tiles.Count; // randomize size change int two = river.Length / 2; int three = two / 2; int four = three / 2; int five = four / 2; int twomin = two / 3; int threemin = three / 3; int fourmin = four / 3; int fivemin = five / 3; // randomize length of each size int count1 = rng.Next(fivemin, five); if (size < 4) { count1 = 0; } int count2 = count1 + rng.Next(fourmin, four); if (size < 3) { count2 = 0; count1 = 0; } int count3 = count2 + rng.Next(threemin, three); if (size < 2) { count3 = 0; count2 = 0; count1 = 0; } int count4 = count3 + rng.Next(twomin, two); // Make sure we are not digging past the river path if (count4 > river.Length) { int extra = count4 - river.Length; while (extra > 0) { if (count1 > 0) { count1--; count2--; count3--; count4--; extra--; } else if (count2 > 0) { count2--; count3--; count4--; extra--; } else if (count3 > 0) { count3--; count4--; extra--; } else if (count4 > 0) { count4--; extra--; } } } // adjust size of river at intersection point if (intersectionSize == 1) { count4 = intersectionCount; count1 = 0; count2 = 0; count3 = 0; } else if (intersectionSize == 2) { count3 = intersectionCount; count1 = 0; count2 = 0; } else if (intersectionSize == 3) { count2 = intersectionCount; count1 = 0; } else if (intersectionSize == 4) { count1 = intersectionCount; } else { count1 = 0; count2 = 0; count3 = 0; count4 = 0; } // dig out the river for (int i = river.Tiles.Count - 1; i >= 0; i--) { WorldTile t = river.Tiles[i]; if (counter < count1 && MaxRiverSize > 3) { t.DigRiver(river, 4); } else if (counter < count2 && MaxRiverSize > 2) { t.DigRiver(river, 3); } else if (counter < count3 && MaxRiverSize > 1) { t.DigRiver(river, 2); } else if (counter < count4 && MaxRiverSize > 0) { t.DigRiver(river, 1); } else { t.DigRiver(river, 0); } counter++; } }
private void GenerateRivers() { int rivercount = RiverCount; Rivers = new List <River>(); int attempts = 0; foreach (int x in Enumerable.Range(0, width).OrderBy(r => rng.Next())) { foreach (int y in Enumerable.Range(0, height).OrderBy(rr => rng.Next())) { WorldTile tile = Tiles[x, y]; attempts++; // validate the tile if (!tile.TerrainData.Collidable) { continue; } if (tile.TerrainData.Rivers.Count > 0) { continue; } if (tile.TerrainData.HeightValue > MinRiverHeight) { // Tile is good to start river from River river = new River(rivercount); // Figure out the direction this river will try to flow river.CurrentDirection = GetLowestNeighbor(tile); // Recursively find a path to water FindPathToWater(tile, river.CurrentDirection, ref river); // Validate the generated river if (river.TurnCount < MinRiverTurns || river.Tiles.Count < MinRiverLength || river.Intersections > MaxRiverIntersections) { //Validation failed - remove this river for (int iii = 0; iii < river.Tiles.Count; iii++) { WorldTile t = river.Tiles[iii]; t.TerrainData.Rivers.Remove(river); } } else if (river.Tiles.Count >= MinRiverLength) { //Validation passed - Add river to list Rivers.Add(river); tile.TerrainData.Rivers.Add(river); rivercount--; } if (rivercount == 0) { goto End; } } } } End: Console.WriteLine(rivercount.ToString() + " : " + attempts); }
private void BuildRiverGroups() { //loop each tile, checking if it belongs to multiple rivers for (var x = 0; x < width; x++) { for (var y = 0; y < height; y++) { WorldTile t = Tiles[x, y]; if (t.TerrainData.Rivers.Count > 1) { // multiple rivers == intersection RiverGroup group = null; // Does a rivergroup already exist for this group? for (int n = 0; n < t.TerrainData.Rivers.Count; n++) { River tileriver = t.TerrainData.Rivers[n]; for (int i = 0; i < RiverGroups.Count; i++) { for (int j = 0; j < RiverGroups[i].Rivers.Count; j++) { River river = RiverGroups[i].Rivers[j]; if (river.ID == tileriver.ID) { group = RiverGroups[i]; } if (group != null) { break; } } if (group != null) { break; } } if (group != null) { break; } } // existing group found -- add to it if (group != null) { for (int n = 0; n < t.TerrainData.Rivers.Count; n++) { if (!group.Rivers.Contains(t.TerrainData.Rivers[n])) { group.Rivers.Add(t.TerrainData.Rivers[n]); } } } else //No existing group found - create a new one { group = new RiverGroup(); for (int n = 0; n < t.TerrainData.Rivers.Count; n++) { group.Rivers.Add(t.TerrainData.Rivers[n]); } RiverGroups.Add(group); } } } } }