public static bool SetOutgoingRiver( Hex source, Hex target, HexDirections direction, ref RiverDigraph riverDigraph ) { if ( riverDigraph.HasOutgoingRiverInDirection( source, direction ) ) { return(false); } if ( !IsValidRiverDestination( source, target ) ) { return(false); } riverDigraph.RemoveOutgoingRivers( source ); if ( riverDigraph.HasIncomingRiverInDirection( source, direction ) ) { riverDigraph.RemoveIncomingRivers( source ); } riverDigraph.RemoveIncomingRivers(target); riverDigraph.AddVerticesAndEdge( new RiverEdge( source, target, direction ) ); return(true); // SetRoad((int)direction, false); }
public HexMapRivers( HexMap hexMap, List <ClimateData> climate, int waterLevel, int elevationMax ) { _hexMap = hexMap; _riverLists = new List <RiverList>(); _riverOriginCandidates = new List <Hex>(); _riverDigraph = new RiverDigraph(); _adjacencyGraph = hexMap.AdjacencyGraph; for (int i = 0; i < _hexMap.SizeSquared; i++) { Hex hex = _hexMap.GetHex(i); if (hex.IsUnderwater) { continue; } ClimateData data = climate[i]; float weight = data.moisture * (hex.elevation - waterLevel) / (elevationMax - waterLevel); if (weight > 0.75) { _riverOriginCandidates.Add(hex); _riverOriginCandidates.Add(hex); } if (weight > 0.5f) { _riverOriginCandidates.Add(hex); } if (weight > 0.25f) { _riverOriginCandidates.Add(hex); } } }
public void RefreshTerrainTypes( ClimateParameters parameters, RiverDigraph riverDigraph ) { int temperatureJitterChannel = Random.Range(0, 4); int rockDesertElevation = parameters.elevationMax - (parameters.elevationMax - parameters.waterLevel) / 2; Holdridge holdridge = new Holdridge(); foreach (Hex hex in _hexMap.Hexes) { float temperature = ClimateArray[hex.Index].temperature; float moisture = ClimateArray[hex.Index].moisture; if (!hex.IsUnderwater) { hex.HoldrigeZone = holdridge.GetHoldridgeZone( temperature, moisture ); continue; int temperatureBand = 0; for ( ; temperatureBand < temperatureBands.Length; temperatureBand++ ) { if (temperature < temperatureBands[temperatureBand]) { break; } } int moistureBand = 0; for (; moistureBand < moistureBands.Length; moistureBand++) { if (moisture < moistureBands[moistureBand]) { break; } } Biome hexBiome = biomes[temperatureBand * 4 + moistureBand]; if (hexBiome.terrain == Terrains.Desert) { if (hex.elevation >= rockDesertElevation) { hexBiome.terrain = Terrains.Stone; } } else if (hex.elevation == parameters.elevationMax) { hexBiome.terrain = Terrains.Snow; } if (hexBiome.terrain == Terrains.Snow) { hexBiome.plant = 0; } if (hexBiome.plant < 3 && riverDigraph.HasRiver(hex)) { hexBiome.plant += 1; } //hex.Biome = hexBiome; //hex.ClimateData = ClimateArray[hex.Index]; } else { LZone lZone; if (hex.elevation == parameters.waterLevel - 1) { int cliffs = 0; int slopes = 0; List <Hex> neighbors; if (_hexMap.TryGetNeighbors(hex, out neighbors)) { foreach (Hex neighbor in neighbors) { int delta = neighbor.elevation - hex.WaterLevel; if (delta == 0) { slopes += 1; } else if (delta > 0) { cliffs += 1; } } } // More than half neighbors at same level. Inlet or // lake, therefore terrain is grass. if (cliffs + slopes > 3) { lZone = LZone.Steppe; } // More than half cliffs, terrain is stone. else if (cliffs > 0) { lZone = LZone.DesertScb; } // More than half slopes, terrain is beach. else if (slopes > 0) { lZone = LZone.DesertH; } // Shallow non-coast, terrain is grass. else { lZone = LZone.Steppe; } } else if (hex.elevation >= parameters.waterLevel) { lZone = LZone.Steppe; } else if (hex.elevation < 0) { lZone = LZone.DesertH; } else { lZone = LZone.WTundra; } // Coldest temperature band produces mud instead of grass. if ( lZone == LZone.Steppe && temperature < temperatureBands[0] ) { lZone = LZone.WTundra; } //hex.Biome = new Biome(terrain, 0); } } }
public void Triangulate( HexMap hexMap, float hexOuterRadius, HexAdjacencyGraph adjacencyGraph, RiverDigraph riverGraph, RoadUndirectedGraph roadGraph, ElevationDigraph elevationGraph ) { _terrainLayer.Clear(); _riversLayer.Clear(); _roadsLayer.Clear(); _openWaterLayer.Clear(); _waterShoreLayer.Clear(); _estuariesLayer.Clear(); _features.Clear(); for (int i = 0; i < Hexes.Length; i++) { Hex current = Hexes[i]; if (current) { Dictionary <HexDirections, Hex> neighbors = adjacencyGraph.GetNeighborByDirection(current); Dictionary <HexDirections, ElevationEdgeTypes> edgeTypes = elevationGraph.GetNeighborEdgeTypes(current); Dictionary <HexDirections, bool> roadEdges = roadGraph.GetNeighborRoads(current); List <HexDirections> borderDirections = adjacencyGraph.GetBorderDirectionsList(current); HexRiverData riverData = riverGraph.GetRiverData(current); TriangulateHex( current, neighbors, borderDirections, hexOuterRadius, riverData, roadEdges, edgeTypes, hexMap.WrapSize, _terrainLayer, _riversLayer, _roadsLayer, _openWaterLayer, _waterShoreLayer, _estuariesLayer, _features ); } } _terrainLayer.Draw(); _riversLayer.Draw(); _roadsLayer.Draw(); _openWaterLayer.Draw(); _waterShoreLayer.Draw(); _estuariesLayer.Draw(); _features.Apply(); }
public Hex Step( HexAdjacencyGraph adjacencyGraph, ref RiverDigraph riverDigraph, float extraLakeProbability, float hexOuterRadius, int waterLevel ) { if (RiverHead.IsUnderwater) { return(null); } int minNeighborElevation = int.MaxValue; int minNeighborWaterLevel = int.MaxValue; List <HexDirections> flowDirections = new List <HexDirections>(); HexDirections direction = HexDirections.Northeast; for ( HexDirections directionCandidate = HexDirections.Northeast; directionCandidate <= HexDirections.Northwest; directionCandidate++ ) { Hex neighborInDirection = adjacencyGraph.TryGetNeighborInDirection( RiverHead, directionCandidate ); if (!neighborInDirection || River.Contains(neighborInDirection)) { continue; } if (neighborInDirection.elevation < minNeighborElevation) { minNeighborElevation = neighborInDirection.elevation; minNeighborWaterLevel = neighborInDirection.WaterLevel; } // If the direction points to the river origin, or to a // neighbor which already has an incoming river, continue. if ( neighborInDirection == RiverHead || riverDigraph.HasIncomingRiver(neighborInDirection) ) { continue; } int delta = neighborInDirection.elevation - RiverHead.elevation; // If the elevation in the given direction is positive, // continue. if (delta > 0) { continue; } // If the direction points away from the river origin and // any neighbors which already have an incoming river, and // the elevation in the given direction is negative or // zero, and the neighbor has an outgoing river, branch // river in this direction. if ( riverDigraph.HasOutgoingRiver(neighborInDirection) ) { SetOutgoingRiver( RiverHead, neighborInDirection, directionCandidate, ref riverDigraph ); River.Add(neighborInDirection); return(neighborInDirection); } // If the direction points away from the river origin and // any neighbors which already have an incoming river, and // the elevation in the given direction is not positive, // and the neighbor does not have an outgoing river in the // given direction... // If the direction is a decline, make the probability for // the branch 4 / 5. if (delta < 0) { flowDirections.Add(directionCandidate); flowDirections.Add(directionCandidate); flowDirections.Add(directionCandidate); } // If the rivers local length is 1, and the direction does // not result in a slight river bend, but rather a straight // river or a corner river, make the probability of the // branch 2 / 5 if ( River.Count == 1 || (directionCandidate != direction.NextClockwise2() && directionCandidate != direction.PreviousClockwise2()) ) { flowDirections.Add(directionCandidate); } flowDirections.Add(directionCandidate); } // If there are no candidates for branching the river... if (flowDirections.Count == 0) { // If the river contains only the river origin... if (River.Count == 1) { // Do nothing and return null return(null); } // If the hex is surrounded by hexes at a higher elevation, // set the water level of the hex to the minium elevation // of all neighbors. if (minNeighborElevation >= RiverHead.elevation) { RiverHead.WaterLevel = RiverHead.elevation; // If the hex is of equal elevation to a neighbor with // a minimum elevation, lower the current hexes // elevation to one below the minimum elevation of all // of its neighbors so that it becomes a small lake // that the river feeds into, and then break out of the // while statement terminating the river in a lake // rather than into the ocean. if (minNeighborElevation == RiverHead.elevation) { RiverHead.SetElevation( minNeighborElevation - 1, hexOuterRadius, _hexMap.WrapSize ); } } return(null); } direction = flowDirections[ Random.Range(0, flowDirections.Count) ]; Hex neighborInRandomDirection = adjacencyGraph.TryGetNeighborInDirection( RiverHead, direction ); SetOutgoingRiver( RiverHead, neighborInRandomDirection, direction, ref riverDigraph ); // If the hex is lower than the minimum elevation of its // neighbors assign a lake based on a specified probability. if ( minNeighborElevation >= RiverHead.elevation && Random.value < extraLakeProbability ) { RiverHead.WaterLevel = RiverHead.elevation; RiverHead.SetElevation( minNeighborElevation - 1, hexOuterRadius, _hexMap.WrapSize ); } River.Add(neighborInRandomDirection); return(neighborInRandomDirection); }