public IEnumerable <HexEdge> GetPath( Hex fromHex, Hex toHex, HexUnit hexUnit, HexAdjacencyGraph graph ) { return(AStarSearch(fromHex, toHex, hexUnit, graph)); // Presentation concerns should not be in this method. // SetPathDistanceLabelAndEnableHighlights(toHex, unit.Speed); }
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 Step( ClimateParameters parameters ) { HexAdjacencyGraph adjacencyGraph = _hexMap.AdjacencyGraph; // Initialize the next climate step. ClimateData[] nextClimates = new ClimateData[ClimateArray.Length]; // Populate the next climate step. for (int i = 0; i < ClimateArray.Length; i++) { nextClimates[i] = new ClimateData(); } // For each hex cell... for (int i = 0; i < _hexMap.SizeSquared; i++) { Hex source = _hexMap.GetHex(i); List <HexEdge> adjacentEdges = adjacencyGraph.GetOutEdgesList(source); // Get the next climate step for that cell. StepClimate( ClimateArray, ref nextClimates, source, adjacentEdges, parameters ); source.clouds = nextClimates[source.Index].clouds; source.moisture = nextClimates[source.Index].moisture; source.temperature = nextClimates[source.Index].clouds; } ClimateArray = nextClimates; }
public static HexAdjacencyGraph FromHexGrid( HexGrid <Hex> hexGrid ) { List <HexEdge> edges = new List <HexEdge>(); for ( int i = 0; i < hexGrid.Rows * hexGrid.Columns; i++ ) { Hex current = hexGrid[i]; foreach ( Hex neighbor in hexGrid.GetNeighbors(i) ) { HexEdge newEdge = new HexEdge( current, neighbor, CubeVector.HexDirectionWrapping( current.CubeCoordinates, neighbor.CubeCoordinates, hexGrid.WrapSize ) ); edges.Add(newEdge); } } HexAdjacencyGraph result = new HexAdjacencyGraph(); result.AddVerticesAndEdgeRange(edges); return(result); }
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); }
/// <summary> /// Search this HexGrid. /// </summary> /// <param name="start"></param> /// <param name="end"></param> /// <param name="unit"></param> /// <returns></returns> private IEnumerable <HexEdge> AStarSearch( Hex start, Hex end, HexUnit unit, HexAdjacencyGraph graph ) { IEnumerable <HexEdge> result; // AlgorithmExtensions.ShortestPathsAStar<Hex, HexEdge>( // graph, // GetPathfindingEdgeWeight, // GetPathfindingHeursitic, // start // ).Invoke(end, out result); return(null); /* int speed = unit.Speed; * * _searchFrontierPhase += 2; * * if (_searchFrontier == null) * { * _searchFrontier = new HexPriorityQueue(); * } * else * { * _searchFrontier.Clear(); * } * * // Temporarily using a list instead of a priority queue. * // Should optimize this later. * // * start.SearchPhase = _searchFrontierPhase; * start.Distance = 0; * _searchFrontier.Enqueue(start); * * while (_searchFrontier.Count > 0) * { * Hex current = _searchFrontier.Dequeue(); * current.SearchPhase += 1; * * if (current == end) * { * return true; * } * * int currentTurn = (current.Distance - 1) / speed; * * for (HexDirection direction = HexDirection.Northeast; direction <= HexDirection.Northwest; direction++) * { * Hex neighbor = current.GetNeighbor(direction); * * if * ( * neighbor == null || * neighbor.SearchPhase > _searchFrontierPhase * ) * { * continue; * } * * if (!unit.IsValidDestination(neighbor)) * { * continue; * } * * int moveCost = unit.GetMoveCost(current, neighbor, direction); * * if (moveCost < 0) * { * continue; * } * * // Wasted movement points are factored into the cost of hexes outside * // the boundary of the first turn by adding the turn number multiplied * // by the speed plus the cost to move into the hex outside the boundary * // of the first turn. This method ensures that the the distances with * // which the algorithm is using to calculate the best path take into * // account wasted movement points. * // * int distance = current.Distance + moveCost; * int turn = (distance - 1) / speed; * * if (turn > currentTurn) { * distance = turn * speed + moveCost; * } * * if (neighbor.SearchPhase < _searchFrontierPhase) { * neighbor.SearchPhase = _searchFrontierPhase; * neighbor.Distance = distance; * neighbor.PathFrom = current; * neighbor.SearchHeuristic = * neighbor.Coordinates.DistanceTo(end.Coordinates); * * _searchFrontier.Enqueue(neighbor); * } * else if (distance < neighbor.Distance) { * int oldPriority = neighbor.SearchPriority; * neighbor.Distance = distance; * neighbor.PathFrom = current; * _searchFrontier.Change(neighbor, oldPriority); * } * } * } * * return false; */ }