public void SetInComgingRiver(HexDirectionEnum direction) { RemoveInComingRiver(); SpecialIndex = 0; HasInComingRiver = true; InComingRive = direction; }
private void TriangulateWithRiverBeginOrEnd(HexCell cell, HexDirectionEnum direction, Vector3 center, EdgeVertices edge) { EdgeVertices m = new EdgeVertices(Vector3.Lerp(center, edge.v1, 0.5f), Vector3.Lerp(center, edge.v5, 0.5f)); m.v3.y = edge.v3.y; TriangulateEdgeStrip(m, weights1, cell.Index, edge, weights1, cell.Index); TriangulateEdgeFan(center, m, cell.Index); if (cell.IsUnderWater) { return; } bool reversed = cell.HasInComingRiver; Vector3 indices; indices.x = indices.y = indices.z = cell.Index; TriangulateRiverQuad(m.v2, m.v4, edge.v2, edge.v4, cell.RiverSurfaceHight, 0.6f, reversed, indices); center.y = m.v2.y = m.v4.y = cell.RiverSurfaceHight; rivers.AddPerturTriangle(center, m.v2, m.v4); if (reversed) { rivers.AddTriangleUV(new Vector2(0.5f, 0.4f), new Vector2(1f, 0.2f), new Vector2(0f, 0.2f)); } else { rivers.AddTriangleUV(new Vector2(0.5f, 0.4f), new Vector2(0f, 0.6f), new Vector2(1f, 0.6f)); } rivers.AddTriangleCellData(indices, weights1); }
//仅处理无临边的情况 private void NoNeighborConnection(HexDirectionEnum direction, HexCell cell, EdgeVertices edge) { Vector3 center = cell.Position; Vector3 bridge = HexMetrics.GetOneBridge(direction); Vector3 v3 = edge.v1 + bridge; Vector3 v4 = edge.v5 + bridge; Vector3 v5 = center + HexMetrics.GetFirstCorner(direction); Vector3 v6 = center + HexMetrics.GetSecondCorner(direction); HexCell prevNeighbor = cell.GetNeighbor(direction.Previous()); HexCell nextNeighbor = cell.GetNeighbor(direction.Next()); v6.y = v5.y = v4.y = v3.y = 0; EdgeVertices edge2 = new EdgeVertices(v5, v6); if (nextNeighbor == null && prevNeighbor != null) { edge2 = new EdgeVertices(v3, v6); HexCell noneCell = new GameObject().AddComponent <HexCell>(); noneCell.Index = cell.Index; TriangulateCorner(edge.v1, cell, v5, prevNeighbor, v3, noneCell); DestroyObject(noneCell.gameObject); } if (cell.Elevation == HexMetrics.elevationDiffer) { TriangulateEdgeTerraces(edge, cell, edge2, cell, cell.HasRoadThroughEdge(direction)); } else { TriangulateEdgeStrip(edge, weights1, cell.Index, edge2, weights1, cell.Index, cell.HasRoadThroughEdge(direction)); } }
/* * 参考资料:https://indienova.com/indie-game-development/hex-map-part-2/ * * v3 v4 * v5 ____________ v6 * \ | | / * v1\|______|/v2 * \ / * \ / * \ / * \/ * center */ /// <summary> /// 绘制六边形 /// </summary> /// <param name="cell"></param> private void Triangulate(HexCell cell) { if (cell == null) { Debug.LogError("Cell is Null"); } ; for (HexDirectionEnum i = 0; i < HexDirectionEnum.Length; i++) { Triangulate(cell, i); } //特征物体 if (!cell.IsUnderWater) { if (!cell.HasRiver && !cell.HasRoads) { feature.AddFeature(cell, cell.Position); } if (cell.IsSpecial) { feature.AddSpecialFeature(cell, cell.Position); } } }
public void AddRoad(HexDirectionEnum direction) { if (RoadElevationSuitable(direction)) { SetRoad((int)direction, true); } }
public void SetOutGoingRiver(HexDirectionEnum direction) { if (HasOutGoingRive && OutGoingRive == direction) { return; } HexCell neighbor = GetNeighbor(direction); if (!IsValidRiverDestination(neighbor)) { return; } RemoveOutGoingRiver(); if (HasInComingRiver && InComingRive == direction) { RemoveInComingRiver(); } SpecialIndex = 0; HasOutGoingRive = true; OutGoingRive = direction; neighbor.SetInComgingRiver(direction.Opposite()); SetRoad((int)direction, false); }
public int GetMoveCost(HexCell fromCell, HexCell toCell, HexDirectionEnum direction) { if (!IsValidDestination(toCell)) { return(-1); } if (fromCell.HasRiver) { return(-1); } if (fromCell.Walled != toCell.Walled) { return(-1); } HexEdgeType edgeType = fromCell.GetEdgeType(toCell); if (edgeType == HexEdgeType.Cliff) { return(-1); } if (fromCell.HasRoadThroughEdge(direction)) { return(1); } int moveCost = edgeType == HexEdgeType.Flat ? 5 : 10; moveCost += toCell.UrbanLevel + toCell.FarmLevel + toCell.PlantLevel; return(moveCost); }
//仅处理无临边的情况 private void NoNeighborConnection(HexDirectionEnum direction, HexCell cell, Vector3 v1, Vector3 v2) { Vector3 center = cell.center; Vector3 bridge = HexMetrics.GetOneBridge(direction); Vector3 v3 = v1 + bridge; Vector3 v4 = v2 + bridge; Vector3 v5 = center + HexMetrics.GetFirstCorner(direction); Vector3 v6 = center + HexMetrics.GetSecondConrner(direction); HexCell prevNeighbor = cell.GetNeighbor(direction.Previous()); HexCell nextNeighbor = cell.GetNeighbor(direction.Next()); Vector3 v7 = v5; Vector3 v8 = v6; if (nextNeighbor == null && prevNeighbor != null) { v7 = v3; v8 = v6; Color firstColor = (cell.color + cell.color + prevNeighbor.color) / 3f; AddTriangle(v1, v5, v3); AddTriangleColor(cell.color, firstColor, cell.color); } AddQuad(v1, v2, v7, v8); AddQuadColor(cell.color); }
private void TriangulateAdjacentToRiver(HexCell cell, HexDirectionEnum direction, Vector3 center, EdgeVertices edge) { if (cell.HasRoads) { TriangulateRoadAdjacentToRiver(direction, cell, center, edge); } if (cell.HasRiverThroughEdge(direction.Next())) { if (cell.HasRiverThroughEdge(direction.Previous())) { center += HexMetrics.GetSolidEdgeMiddle(direction) * (HexMetrics.innerToOuter * 0.5f); } else if (cell.HasRiverThroughEdge(direction.Previous(2))) { center += HexMetrics.GetFirstSolidCorner(direction) * 0.25f; } } else if (cell.HasRiverThroughEdge(direction.Previous()) && cell.HasRiverThroughEdge(direction.Next(2))) { center += HexMetrics.GetSecondSolidCorner(direction) * 0.25f; } EdgeVertices m = new EdgeVertices(Vector3.Lerp(center, edge.v1, 0.5f), Vector3.Lerp(center, edge.v5, 0.5f)); TriangulateEdgeStrip(m, weights1, cell.Index, edge, weights1, cell.Index); TriangulateEdgeFan(center, m, cell.Index); }
private bool RoadElevationSuitable(HexDirectionEnum direction) { if (IsSpecial || GetNeighbor(direction).IsSpecial) { return(false); } return(!roads[(int)direction] && !HasRiverThroughEdge(direction) && GetElevationDifference(direction) <= 1); }
//对面三角 public static HexDirectionEnum Opposite(this HexDirectionEnum direction) { direction += (int)HexDirectionEnum.Length / 2; if (direction >= HexDirectionEnum.Length) { direction -= (int)HexDirectionEnum.Length; } return(direction); }
/* * e.v1 _________________ e.v5 * \ | | | / * m.v1\__|___|___|__/m.v5 * \ | | | / * \|___|___|/ * cL c cR * e.v1 ~ e.v5 平均分成4分 每份是1/4 * m/e = 3/4,所以 m.v1 ~ m.v5 是1/6,1/4,1/4,1/6 */ /// <summary> /// 河道三角化 /// </summary> /// <param name="cell"></param> /// <param name="direction"></param> /// <param name="center"></param> /// <param name="edge"></param> private void TriangulateWithRiver(HexCell cell, HexDirectionEnum direction, Vector3 center, EdgeVertices edge) { Vector3 centerL; Vector3 centerR; if (cell.HasRiverThroughEdge(direction.Opposite())) { centerL = center + HexMetrics.GetFirstSolidCorner(direction.Previous()) * 1 / 4f; centerR = center + HexMetrics.GetSecondSolidCorner(direction.Next()) * 1 / 4f; } else if (cell.HasRiverThroughEdge(direction.Previous())) { centerL = Vector3.Lerp(center, edge.v1, 2 / 3f); centerR = center; } else if (cell.HasRiverThroughEdge(direction.Next())) { centerL = center; centerR = Vector3.Lerp(center, edge.v5, 2 / 3f); } else if (cell.HasRiverThroughEdge(direction.Next(2))) { centerL = center; centerR = center + HexMetrics.GetSolidEdgeMiddle(direction.Next()) * (0.5f * HexMetrics.innerToOuter); } else { centerL = center + HexMetrics.GetSolidEdgeMiddle(direction.Previous()) * (0.5f * HexMetrics.innerToOuter); centerR = center; } center = Vector3.Lerp(centerL, centerR, 0.5f); EdgeVertices m = new EdgeVertices(Vector3.Lerp(centerL, edge.v1, 0.5f), Vector3.Lerp(centerR, edge.v5, 0.5f), 1 / 6f); m.v3.y = center.y = edge.v3.y; TriangulateEdgeStrip(m, weights1, cell.Index, edge, weights1, cell.Index); AddTerrainPerturTriangle(centerL, m.v1, m.v2); AddTerrainQuad(centerL, center, m.v2, m.v3); AddTerrainQuad(center, centerR, m.v3, m.v4); AddTerrainPerturTriangle(centerR, m.v4, m.v5); Vector3 indices; indices.x = indices.y = indices.z = cell.Index; terrain.AddTriangleCellData(indices, weights1); terrain.AddQuadCellData(indices, weights1); terrain.AddQuadCellData(indices, weights1); terrain.AddTriangleCellData(indices, weights1); bool reversed = cell.InComingRive == direction; TriangulateRiverQuad(centerL, centerR, m.v2, m.v4, cell.RiverSurfaceHight, 0.4f, reversed, indices); TriangulateRiverQuad(m.v2, m.v4, edge.v2, edge.v4, cell.RiverSurfaceHight, 0.6f, reversed, indices); }
//获取边的第二个(v4)坐标点 public static Vector3 GetSecondCorner(HexDirectionEnum direction) { direction += 1; if (direction >= HexDirectionEnum.Length) { direction -= corners.Length; } return(GetFirstCorner(direction)); }
public static HexDirectionEnum Next(this HexDirectionEnum direction, int num) { direction += num; if (direction >= HexDirectionEnum.Length) { direction -= (int)HexDirectionEnum.Length; } return(direction); }
public static HexDirectionEnum Previous(this HexDirectionEnum direction, int num) { direction -= num; if (direction < 0) { direction += (int)HexDirectionEnum.Length; } return(direction); }
private void Triangulate(HexCell cell, HexDirectionEnum direction) { Vector3 center = cell.Position; //绘制内三角 Vector3 v1 = center + HexMetrics.GetFirstSolidCorner(direction); Vector3 v2 = center + HexMetrics.GetSecondSolidCorner(direction); EdgeVertices edge = new EdgeVertices(v1, v2); if (cell.HasRiver) { if (cell.HasRiverThroughEdge(direction)) { edge.v3.y = cell.StreamBedHight; if (cell.HasRiverBeginOrEnd) { TriangulateWithRiverBeginOrEnd(cell, direction, center, edge); } else { TriangulateWithRiver(cell, direction, center, edge); } } else { TriangulateAdjacentToRiver(cell, direction, center, edge); if (!cell.IsUnderWater && !cell.HasRoadThroughEdge(direction)) { feature.AddFeature(cell, (center + edge.v1 + edge.v5) * (1 / 3f)); } } } else { TriangulateWithoutRiver(cell, direction, center, edge); if (!cell.IsUnderWater && !cell.HasRoadThroughEdge(direction)) { feature.AddFeature(cell, (center + edge.v1 + edge.v5) * (1 / 3f)); } } //绘制外梯形,为了避免重复绘制,两个三角形只绘制一次 if (DirectionOnRight(direction)) { TrangulateConnection(direction, cell, edge); } /*else if ( cell.GetNeighbor( direction ) == null ) { * NoNeighborConnection( direction , cell , edge ) ; * }*/ if (cell.IsUnderWater) { TriangulateWater(direction, cell, center); } }
public static Vector3 GetSolidEdgeMiddle(HexDirectionEnum direction) { HexDirectionEnum next = direction + 1; if (next >= HexDirectionEnum.Length) { next -= HexDirectionEnum.Length; } return((corners[(int)direction] + corners[(int)next]) * (0.5f * solidFactor)); }
//风化地形 private void ErodeLand() { List <HexCell> erodibleCells = ListPool <HexCell> .Get(); for (int i = 0; i < cellCount; i++) { HexCell cell = hexGrid.GetCell(i); if (IsErodible(cell)) { erodibleCells.Add(cell); } } int targetErodibleCount = (int)(erodibleCells.Count * (100 - erosionPercentage) * 0.01f); while (erodibleCells.Count > targetErodibleCount) { int index = Random.Range(0, erodibleCells.Count); HexCell cell = erodibleCells[index]; HexCell targetCell = GetErosionTarget(cell); cell.Elevation -= 1; targetCell.Elevation += 1; if (!IsErodible(cell)) { erodibleCells[index] = erodibleCells[erodibleCells.Count - 1]; erodibleCells.RemoveAt(erodibleCells.Count - 1); } for (HexDirectionEnum d = 0; d < HexDirectionEnum.Length; d++) { HexCell neighbor = cell.GetNeighbor(d); if (neighbor && neighbor.Elevation == cell.Elevation + 2 && !erodibleCells.Contains(neighbor)) { erodibleCells.Add(neighbor); } } if (IsErodible(targetCell) && !erodibleCells.Contains(targetCell)) { erodibleCells.Add(targetCell); } for (HexDirectionEnum d = 0; d < HexDirectionEnum.Length; d++) { HexCell neighbor = targetCell.GetNeighbor(d); if (neighbor && neighbor != cell && neighbor.Elevation == (targetCell.Elevation + 1) && !IsErodible(neighbor)) { erodibleCells.Remove(neighbor); } } } ListPool <HexCell> .Add(erodibleCells); }
private void ValidateDrag(HexCell currentCell) { for (HexDirectionEnum i = 0; i < HexDirectionEnum.Length; i++) { if (previousCell.GetNeighbor(i) == currentCell) { dragDirection = i; isDrag = true; return; } } isDrag = false; }
private bool IsErodible(HexCell cell) { int erodibleElevation = cell.Elevation - 2; for (HexDirectionEnum d = 0; d < HexDirectionEnum.Length; d++) { HexCell neighbor = cell.GetNeighbor(d); if (neighbor && neighbor.Elevation <= erodibleElevation) { return(true); } } return(false); }
private void TriangulateWater(HexDirectionEnum direction, HexCell cell, Vector3 center) { center.y = cell.WaterSurfaceHight; HexCell neighbor = cell.GetNeighbor(direction); if (neighbor != null && !neighbor.IsUnderWater) { TriangulateWaterShore(direction, cell, neighbor, center); } else { TriangulateOpenWater(direction, cell, neighbor, center); } }
private int SinkTerrain(int chunkSize, int budget, MapRegion region) { searchFrontierPhase += 1; HexCell firestCell = GetRandomCell(region); firestCell.SearchPhase = searchFrontierPhase; firestCell.Distance = 0; firestCell.SearchHeuristic = 0; searchFrontier.Enqueue(firestCell); HexCoordinates center = firestCell.coordinates; int sink = Random.value < highRiseProbability ? 2 : 1; int size = 0; while (size < chunkSize && searchFrontier.Count > 0) { HexCell current = searchFrontier.Dequeue(); int originalElevation = current.Elevation; int newElevation = originalElevation - sink; if (newElevation < elevationMinimum) { continue; } current.Elevation = newElevation; ; if (originalElevation >= waterLevel && newElevation < waterLevel) { budget += 1; } size += 1; for (HexDirectionEnum d = 0; d < HexDirectionEnum.Length; d++) { HexCell neighbor = current.GetNeighbor(d); if (neighbor && neighbor.SearchPhase < searchFrontierPhase) { neighbor.SearchPhase = searchFrontierPhase; neighbor.Distance = neighbor.coordinates.DistanceTo(center); neighbor.SearchHeuristic = Random.value < jitterProbability ? 1 : 0; searchFrontier.Enqueue(neighbor); } } } searchFrontier.Clear(); return(budget); }
private Vector2 GetRoadInterpolators(HexDirectionEnum direction, HexCell cell) { Vector2 interpolators = new Vector2(); if (cell.HasRoadThroughEdge(direction)) { interpolators.x = interpolators.y = 0.5f; } else { interpolators.x = cell.HasRoadThroughEdge(direction.Previous( )) ? 0.5f : 0.25f; interpolators.y = cell.HasRoadThroughEdge(direction.Next( )) ? 0.5f : 0.25f; } return(interpolators); }
private void TriangulateWithoutRiver(HexCell cell, HexDirectionEnum direction, Vector3 center, EdgeVertices edge) { TriangulateEdgeFan(center, edge, cell.Index); if (cell.IsUnderWater) { return; } if (cell.HasRoads) { Vector2 interpoltors = GetRoadInterpolators(direction, cell); TriangulateRoad(center, Vector3.Lerp(center, edge.v1, interpoltors.x), Vector3.Lerp(center, edge.v5, interpoltors.y), edge, cell.HasRoadThroughEdge(direction), cell.Index); } }
/* * 参考资料:https://indienova.com/indie-game-development/hex-map-part-2/ * * v3 v4 * v5 ____________ v6 * \ | | / * v1\|______|/v2 * \ / * \ / * \ / * \/ * center */ /// <summary> /// 绘制六边形 /// </summary> /// <param name="cell"></param> private void Triangulate(HexCell cell) { Vector3 center = cell.center; for (HexDirectionEnum i = 0; i < HexDirectionEnum.Length; i++) { //绘制内三角 Vector3 v1 = center + HexMetrics.GetFirstSolidCorner(i); Vector3 v2 = center + HexMetrics.GetSecondSolidConrner(i); AddTriangle(center, v1, v2); AddTriangleColor(cell.color, cell.color, cell.color); /*Vector3 bridge = HexMetrics.GetBridge( i ) ; * Vector3 v3 = v1 + bridge; * Vector3 v4 = v2 + bridge; * * AddQuad( v1 , v2 , v3 , v4 ) ; * * HexCell prevNeighbor = cell.GetNeighbor( i.Previous() ) ?? cell ; * HexCell neighbor = cell.GetNeighbor( i ) ?? cell ; * HexCell nextNeighbor = cell.GetNeighbor( i.Next() ) ?? cell ; * * Color firstColor = (cell.color + prevNeighbor.color + neighbor.color) / 3f ; * Color secondColor = (cell.color + neighbor.color + nextNeighbor.color) / 3f ; * Color bridgeColor = (cell.color + neighbor.color) * 0.5f ; * * AddQuadColor( cell.color , bridgeColor) ; * * AddTriangle( v1,center+HexMetrics.GetFirstCorner( i ),v3 ); * AddTriangleColor( cell.color,firstColor,bridgeColor ); * * AddTriangle(v2, v4, center + HexMetrics.GetSecondConrner(i)); * AddTriangleColor(cell.color, bridgeColor, secondColor);*/ //绘制外梯形,为了避免重复绘制,两个三角形只绘制一次 if (i == HexDirectionEnum.TopRight || i == HexDirectionEnum.Right || i == HexDirectionEnum.BottomRight) { RightTrangulateConnection(i, cell, v1, v2); } else if (cell.GetNeighbor(i) == null) { NoNeighborConnection(i, cell, v1, v2); } } }
private HexCell GetErosionTarget(HexCell cell) { List <HexCell> candidates = ListPool <HexCell> .Get(); int erodibleElevation = cell.Elevation - 2; for (HexDirectionEnum d = 0; d < HexDirectionEnum.Length; d++) { HexCell neighbor = cell.GetNeighbor(d); if (neighbor && neighbor.Elevation <= erodibleElevation) { candidates.Add(neighbor); } } HexCell target = candidates[Random.Range(0, candidates.Count)]; ListPool <HexCell> .Add(candidates); return(target); }
private void RightTrangulateConnection(HexDirectionEnum direction, HexCell cell, Vector3 v1, Vector3 v2) { HexCell neighbor = cell.GetNeighbor(direction); if (neighbor == null) { NoNeighborConnection(direction, cell, v1, v2); return; } Vector3 bridge = HexMetrics.GetTwoBridge(direction); Vector3 v3 = v1 + bridge; Vector3 v4 = v2 + bridge; AddQuad(v1, v2, v3, v4); AddQuadColor(cell.color, neighbor.color); HexCell nextNeighbor = cell.GetNeighbor(direction.Next()); if (nextNeighbor != null) { AddTriangle(v2, v4, v2 + HexMetrics.GetTwoBridge(direction.Next())); AddTriangleColor(cell.color, neighbor.color, nextNeighbor.color); } else { //绘制缺失的小三角 AddTriangle(v2, v4, cell.center + HexMetrics.GetSecondConrner(direction)); AddTriangleColor(cell.color, neighbor.color, (cell.color + neighbor.color) * 0.5f); } //绘制缺失的小三角 HexCell prevNeighbor = cell.GetNeighbor(direction.Previous()); if (prevNeighbor == null) { AddTriangle(v1, cell.center + HexMetrics.GetFirstCorner(direction), v3); AddTriangleColor(cell.color, (cell.color + cell.color + neighbor.color) / 3f, neighbor.color); } }
private void TriangulateOpenWater(HexDirectionEnum direction, HexCell cell, HexCell neighbor, Vector3 center) { Vector3 c1 = center + HexMetrics.GetWaterFirstCorner(direction); Vector3 c2 = center + HexMetrics.GetWaterSecondCorner(direction); water.AddPerturTriangle(center, c1, c2); Vector3 indices; indices.x = indices.y = indices.z = cell.Index; water.AddTriangleCellData(indices, weights1); if (neighbor != null && DirectionOnRight(direction)) { Vector3 bridge = HexMetrics.GetWaterBridge(direction); Vector3 e1 = c1 + bridge; Vector3 e2 = c2 + bridge; water.AddPerturQuad(c1, c2, e1, e2); indices.y = neighbor.Index; water.AddQuadCellData(indices, weights1, weights2); if (direction == HexDirectionEnum.TopRight || direction == HexDirectionEnum.Right) { HexCell nextNeighbor = cell.GetNeighbor(direction.Next()); if (nextNeighbor == null || !nextNeighbor.IsUnderWater) { return; } water.AddPerturTriangle(c2, e2, c2 + HexMetrics.GetWaterBridge(direction.Next())); indices.z = nextNeighbor.Index; water.AddTriangleCellData(indices, weights1, weights2, weights3); } } }
public int GetElevationDifference(HexDirectionEnum direction) { int difference = Elevation - GetNeighbor(direction).Elevation; return(Mathf.Abs(difference)); }
public bool HasRoadThroughEdge(HexDirectionEnum direction) { return(roads[(int)direction]); }