//e1 = solid edge vertices void TriangulatePoliticalBorder(HexDirection direction, HexCell cell, EdgeVertices e1) { if (cell.IsNeighborFriendly(direction)) { return; } Vector3 center = cell.Position; EdgeVertices e3 = new EdgeVertices( center + HexMetrics.GetFirstCorner(direction), center + HexMetrics.GetSecondCorner(direction) ); politicalBorders.AddQuad(e1.v1, e1.v2, e3.v1, e3.v2); politicalBorders.AddQuad(e1.v2, e1.v3, e3.v2, e3.v3); politicalBorders.AddQuad(e1.v3, e1.v4, e3.v3, e3.v4); politicalBorders.AddQuad(e1.v4, e1.v5, e3.v4, e3.v5); politicalBorders.AddQuadUV(0f, 0f, 1f, 0f); politicalBorders.AddQuadUV(0f, 0f, 1f, 0f); politicalBorders.AddQuadUV(0f, 0f, 1f, 0f); politicalBorders.AddQuadUV(0f, 0f, 1f, 0f); HexCell neighbor = cell.GetNeighbor(direction); HexCell nextNeighbor = cell.GetNeighbor(direction.Next()); if (cell.IsNeighborFriendly(direction.Next())) { Debug.Log("corner should be added"); politicalBorders.AddTriangle(e3.v5, e1.v5 + HexMetrics.GetBridge(direction.Next()), e1.v5); politicalBorders.AddTriangleUV(new Vector2(0f, 0f), new Vector2(0f, 1f), new Vector2(0f, 1f)); } }
//仅处理无临边的情况 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)); } }
void Triangulate(HexDirection direction, HexCell cell) { Vector3 center = cell.transform.localPosition; Vector3 v1 = center + HexMetrics.GetFirstSolidCorner(direction); Vector3 v2 = center + HexMetrics.GetSecondSolidCorner(direction); Vector3 bridge = HexMetrics.GetBridge(direction); Vector3 v3 = v1 + bridge; Vector3 v4 = v2 + bridge; AddTriangle(center, v1, v2); AddTriangleColor(cell.color); AddQuad(v1, v2, v3, v4); HexCell prevNeighbor = cell.GetNeighbor(direction.Previous()) ?? cell; HexCell neighbor = cell.GetNeighbor(direction) ?? cell; HexCell nextNeighbor = cell.GetNeighbor(direction.Next()) ?? cell; Color bridgeColor = (cell.color + neighbor.color) * 0.5f; AddQuadColor(cell.color, bridgeColor); AddTriangle(v1, center + HexMetrics.GetFirstCorner(direction), v3); AddTriangleColor( cell.color, (cell.color + prevNeighbor.color + neighbor.color) / 3f, bridgeColor ); AddTriangle(v2, v4, center + HexMetrics.GetSecondCorner(direction)); AddTriangleColor( cell.color, bridgeColor, (cell.color + neighbor.color + nextNeighbor.color) / 3f ); }
private void OnDrawGizmos() { Gizmos.color = Color.black; for (HexDirection direction = HexDirection.NE; direction <= HexDirection.NW; direction++) { Gizmos.DrawLine(transform.TransformPoint(HexMetrics.GetFirstCorner(direction)) , transform.TransformPoint(HexMetrics.GetSecondCorner(direction))); } }
void Triangulate(HexDirection direction, HexCell cell) { Vector3 center = cell.transform.localPosition; map.AddTriangle( center, center + _hexMetrics.GetFirstCorner(direction), center + _hexMetrics.GetSecondCorner(direction) ); map.AddTriangleColor(cell.Color); }
//cellPos를 중심으로 육각 mesh를 생성 void Triangulate(Vector3 cellPos) { for (HexDirection direction = HexDirection.NE; direction <= HexDirection.NW; direction++) { AddTriangle( cellPos, cellPos + HexMetrics.GetFirstCorner(direction), cellPos + HexMetrics.GetSecondCorner(direction) ); AddTriangleColor(gridColor); } }
public void secondCornerTest() { float innRad = HexMetrics.innerRadius; float outRad = HexMetrics.outerRadius; Vector3 expected = new Vector3(innRad, 0f, 0.5f * outRad); HexDirection direction = HexDirection.NE; Vector3 actual = HexMetrics.GetSecondCorner(direction); Assert.AreEqual(expected, actual); }
public void Outline(HexCell cell) { Vector3 center = cell.transform.localPosition; var points = new Vector3[lengthOfLineRenderer]; int i = 0; for (HexDirection d = HexDirection.NE; d <= HexDirection.NW; d++) { points[i++] = center + HexMetrics.GetFirstCorner(d) + offset; points[i++] = center + HexMetrics.GetSecondCorner(d) + offset; } lineRenderer.SetPositions(points); }
/* Creates a quad stretching from a cell's solid boundary to its true edge*/ void TriangulateEdge(HexDirection direction, HexCell cell) { Vector3 center = cell.transform.localPosition; EdgeVertices e1 = new EdgeVertices( center + HexMetrics.GetFirstSolidCorner(direction), center + HexMetrics.GetSecondSolidCorner(direction) ); EdgeVertices e2 = new EdgeVertices( center + HexMetrics.GetFirstCorner(direction), center + HexMetrics.GetSecondCorner(direction) ); edgeMesh.AddQuad(e1, e2); }
void Triangulate(HexDirection direction, HexCell cell) { Vector3 center = cell.transform.localPosition; terrain.AddTriangle( center, center + HexMetrics.GetFirstCorner(direction), center + HexMetrics.GetSecondCorner(direction) ); HexCell prevNeighbor = cell.GetNeighbor(direction.Previous()) ?? cell; HexCell neighbor = cell.GetNeighbor(direction) ?? cell; HexCell nextNeighbor = cell.GetNeighbor(direction.Next()) ?? cell; terrain.AddTriangleColor(cell.Color); }
void Triangulate(HexDirection direction, HexCell cell) { Vector3 center = cell.transform.localPosition; Vector3 v1 = center + HexMetrics.GetFirstSolidCorner(direction); Vector3 v2 = center + HexMetrics.GetSecondSolidCorner(direction); Vector3 v5 = center + HexMetrics.GetFirstCorner(direction); Vector3 v6 = center + HexMetrics.GetSecondCorner(direction); AddTriangle(center, v1, v2); AddTriangleColor(cell.color); if (direction <= HexDirection.SE) { TriangulateConnection(direction, cell, v1, v2); } }
void TriangulateWallStrip(HexDirection d, HexCell cell) { HexDirection castDir = d.Opposite(); HexCell n = cell.GetNeighbor(castDir); if (CheckCellValid(n)) { //limit to prevent infinite loops if something goes wrong for (int i = 0; i < 10; i++) { HexCell n2 = n.GetNeighbor(castDir); if (CheckCellValid(n2)) { n = n2; } else { break; } } //n is final cell Vector3 offset = new Vector3(0, wallHeight, 0); EdgeVertices e1 = new EdgeVertices( cell.transform.localPosition + HexMetrics.GetFirstSolidCorner(castDir), n.transform.localPosition + HexMetrics.GetSecondSolidCorner(d) ); EdgeVertices e2 = new EdgeVertices( e1.v1 + offset, e1.v2 + offset ); wallMesh.AddQuad(e1, e2); EdgeVertices e3 = new EdgeVertices( offset + cell.transform.localPosition + HexMetrics.GetFirstCorner(castDir), offset + n.transform.localPosition + HexMetrics.GetSecondCorner(d) ); wallMesh.AddQuad(e2, e3); EdgeVertices e4 = new EdgeVertices( offset + cell.transform.localPosition + HexMetrics.GetFirstCorner(castDir.Previous()), offset + n.transform.localPosition + HexMetrics.GetSecondCorner(d.Next()) ); wallMesh.AddQuad(e3, e4); } }
/* creates the stage boundaries */ void TriangulateOuterWallPanelCorner(HexDirection direction, HexCell cell, HexCell neighbor) { Vector3 offset = new Vector3(0, wallHeight, 0); Vector3 endpoint = offset + cell.transform.localPosition + HexMetrics.GetSecondCorner(direction); EdgeVertices e1 = new EdgeVertices( cell.transform.localPosition + HexMetrics.GetSecondSolidCorner(direction), neighbor.transform.localPosition + HexMetrics.GetFirstSolidCorner(direction.Previous()) ); EdgeVertices e2 = new EdgeVertices( e1.v1 + offset, e1.v2 + offset ); edgeMesh.AddQuad(e1, e2); edgeMesh.AddTriangle(e2.v1, endpoint, e2.v2); }
/*** Unused? ***/ /* creates the stage boundaries */ void TriangulateOuterWallPanel(HexDirection direction, HexCell cell) { Vector3 center = cell.transform.localPosition; Vector3 offset = new Vector3(0, wallHeight, 0); EdgeVertices e1 = new EdgeVertices( center + HexMetrics.GetFirstSolidCorner(direction), center + HexMetrics.GetSecondSolidCorner(direction) ); EdgeVertices e2 = new EdgeVertices( e1.v1 + offset, e1.v2 + offset ); EdgeVertices e3 = new EdgeVertices( center + offset + HexMetrics.GetFirstCorner(direction), center + offset + HexMetrics.GetSecondCorner(direction) ); wallMesh.AddQuad(e1, e2); wallMesh.AddQuad(e2, e3); }
void Triangulate(HexDirection direction, HexCell cell) { //纯色区域三角化使用单一颜色 Vector3 center = cell.transform.localPosition; Vector3 v1 = center + HexMetrics.GetFirstSolidCorner(direction); Vector3 v2 = center + HexMetrics.GetSecondSolidCorner(direction); AddTriangle(center, v1, v2); AddTriangleColor(cell.color); //梯形混色区域 Vector3 bridge = HexMetrics.GetBridge(direction); Vector3 v3 = v1 + bridge; Vector3 v4 = v2 + bridge; AddQuad(v1, v2, v3, v4); HexCell prevNeighbor = cell.GetNeighbor(direction.Previous()) ?? cell; HexCell neighbor = cell.GetNeighbor(direction) ?? cell; HexCell nextNeighbor = cell.GetNeighbor(direction.Next()) ?? cell; AddQuadColor(cell.color, (cell.color + prevNeighbor.color + neighbor.color) * 0.5f); //补上被剔除的两个三角形(第一个三角形三个顶点的颜色分别是v1本色,2三个六边形混色,3桥色) Color bridgeColor = (cell.color + neighbor.color) * 0.5f; // AddQuadColor(cell.color, bridgeColor); AddTriangle(v1, center + HexMetrics.GetFirstCorner(direction), v3); AddExcludedTriangleColor( cell.color, (cell.color + prevNeighbor.color + neighbor.color) / 3f, bridgeColor); AddTriangle(v2, v4, center + HexMetrics.GetSecondCorner(direction)); AddExcludedTriangleColor( cell.color, bridgeColor, (cell.color + neighbor.color + nextNeighbor.color) / 3f ); }
private void Triangulate(HexDirection direction, HexCell cell) { Vector3 center = cell.transform.localPosition; Vector3 v1 = center + HexMetrics.GetFirstSolidCorner(direction); Vector3 v2 = center + HexMetrics.GetSecondSolidCorner(direction); AddTriangle(center, v1, v2); AddTriangleColor(cell.CellColor); Vector3 v3 = center + HexMetrics.GetFirstCorner(direction); Vector3 v4 = center + HexMetrics.GetSecondCorner(direction); AddQuad(v1, v2, v3, v4); HexCell previousNeighbour = cell.GetNeighbour(direction.Previous()) ?? cell; HexCell neighbour = cell.GetNeighbour(direction) ?? cell; HexCell nextNeighbour = cell.GetNeighbour(direction.Next()) ?? cell; AddQuadColor( cell.CellColor, cell.CellColor, (cell.CellColor + previousNeighbour.CellColor + neighbour.CellColor) / 3f, (cell.CellColor + neighbour.CellColor + nextNeighbour.CellColor) / 3f); }
/// <summary> /// Creates road geometry when there is a river in the cell. /// </summary> void TriangulateRoadAdjacentToRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) { bool hasRoadThroughEdge = cell.HasRoadThroughEdge(direction); bool previousHasRiver = cell.HasRiverThroughEdge(direction.Previous()); bool nextHasRiver = cell.HasRiverThroughEdge(direction.Next()); Vector2 interpolators = GetRoadInterpolators(direction, cell); Vector3 roadCenter = center; // When there is a river start/end or a river zig-zag then we only need to offset road center // If there is a straight section of river cutting through or a smooth turn then those divide the road network if (cell.HasRiverBeginOrEnd) // If this is river start or river end { roadCenter += HexMetrics.GetSolidEdgeMiddle(cell.RiverBeginOrEndDirection.Opposite()) * (1f / 3f); } else if (cell.IncomingRiver == cell.OutgoingRiver.Opposite()) // If this is a river section cutting cell in the middle { Vector3 corner; if (previousHasRiver) { if (!hasRoadThroughEdge && !cell.HasRoadThroughEdge(direction.Next())) { return; // Dont draw on the other side of the river } corner = HexMetrics.GetSecondSolidCorner(direction); } else { if (!hasRoadThroughEdge && !cell.HasRoadThroughEdge(direction.Previous())) { return; // Dont draw on the other side of the river } corner = HexMetrics.GetFirstSolidCorner(direction); } roadCenter += corner * 0.5f; // Prevent duplicate bridges and add a bridge if road on both sides if (cell.IncomingRiver == direction.Next() && ( cell.HasRoadThroughEdge(direction.Next2()) || cell.HasRoadThroughEdge(direction.Opposite()) )) { Features.AddBridge(roadCenter, center - corner * 0.5f); } center += corner * 0.25f; } else if (cell.IncomingRiver == cell.OutgoingRiver.Previous()) // Check if zig-zag and offset { roadCenter -= HexMetrics.GetSecondCorner(cell.IncomingRiver) * 0.2f; } else if (cell.IncomingRiver == cell.OutgoingRiver.Next()) // Check if zig-zag and offset { roadCenter -= HexMetrics.GetFirstCorner(cell.IncomingRiver) * 0.2f; } else if (previousHasRiver && nextHasRiver) // Check smooth curve (inside of the curve) { if (!hasRoadThroughEdge) { return; // Dont draw on the other side of the river } Vector3 offset = HexMetrics.GetSolidEdgeMiddle(direction) * HexMetrics.InnerToOuter; roadCenter += offset * 0.7f; center += offset * 0.5f; } else // Smooth curve (outside of the curve) { HexDirection middle; if (previousHasRiver) { middle = direction.Next(); } else if (nextHasRiver) { middle = direction.Previous(); } else { middle = direction; } if (!cell.HasRoadThroughEdge(middle) && !cell.HasRoadThroughEdge(middle.Previous()) && !cell.HasRoadThroughEdge(middle.Next())) { return; // Dont draw on the other side of the river } // Set center and add bridge Vector3 offset = HexMetrics.GetSolidEdgeMiddle(middle); roadCenter += offset * 0.25f; // Prevent duplicate bridges and road on both sides if (direction == middle && cell.HasRoadThroughEdge(direction.Opposite())) { Features.AddBridge(roadCenter, center - offset * (HexMetrics.InnerToOuter * 0.7f)); } } Vector3 mL = Vector3.Lerp(roadCenter, e.v1, interpolators.x); Vector3 mR = Vector3.Lerp(roadCenter, e.v5, interpolators.y); TriangulateRoad(roadCenter, mL, mR, e, hasRoadThroughEdge, cell.Index); // Create auxiliary geometry if (previousHasRiver) { TriangulateRoadEdge(roadCenter, center, mL, cell.Index); } if (nextHasRiver) { TriangulateRoadEdge(roadCenter, mR, center, cell.Index); } }
void TriangulateRoadAdjacentToRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) { bool hasRoadThroughEdge = cell.HasRoadThroughEdge(direction); bool previousHasRiver = cell.HasRiverThroughEdge(direction.Previous()); bool nextHasRiver = cell.HasRiverThroughEdge(direction.Next()); Vector2 interpolators = GetRoadInterpolators(direction, cell); Vector3 roadCenter = center; // Push road center away from river if (cell.HasRiverBeginOrEnd) { roadCenter += HexMetrics.GetSolidEdgeMiddle(cell.RiverBeginOrEndDirection.Opposite()) * (1f / 3f); } // Disconnect road on opposite side of river else if (cell.IncomingRiver == cell.OutgoingRiver.Opposite()) { Vector3 corner; if (previousHasRiver) { if (!hasRoadThroughEdge && !cell.HasRoadThroughEdge(direction.Next())) { return; } corner = HexMetrics.GetSecondSolidCorner(direction); } else { if (!hasRoadThroughEdge && !cell.HasRoadThroughEdge(direction.Previous())) { return; } corner = HexMetrics.GetFirstSolidCorner(direction); } roadCenter += corner * 0.5f; center += corner * 0.25f; } else if (cell.IncomingRiver == cell.OutgoingRiver.Previous()) { roadCenter -= HexMetrics.GetSecondCorner(cell.IncomingRiver) * 0.2f; } else if (cell.IncomingRiver == cell.OutgoingRiver.Next()) { roadCenter -= HexMetrics.GetFirstCorner(cell.IncomingRiver) * 0.2f; } else if (previousHasRiver && nextHasRiver) { if (!hasRoadThroughEdge) { return; } Vector3 offset = HexMetrics.GetSolidEdgeMiddle(direction) * HexMetrics.innerToOuter; roadCenter += offset * 0.7f; center += offset * 0.5f; } else { HexDirection middle; if (previousHasRiver) { middle = direction.Next(); } else if (nextHasRiver) { middle = direction.Previous(); } else { middle = direction; } if (!cell.HasRoadThroughEdge(middle) && !cell.HasRoadThroughEdge(middle.Previous()) && !cell.HasRoadThroughEdge(middle.Next())) { return; } roadCenter += HexMetrics.GetSolidEdgeMiddle(middle) * 0.25f; } Vector3 mL = Vector3.Lerp(roadCenter, e.v1, interpolators.x); Vector3 mR = Vector3.Lerp(roadCenter, e.v5, interpolators.y); TriangulateRoad(roadCenter, mL, mR, e, hasRoadThroughEdge); // Close gaps in road created by river if (previousHasRiver) { TriangulateRoadEdge(roadCenter, center, mL); } if (nextHasRiver) { TriangulateRoadEdge(roadCenter, mR, center); } }
/// <summary> /// 三角化有河流的六边形内的道路 /// </summary> /// <param name="direction"></param> /// <param name="cell"></param> /// <param name="center">六边形的中心</param> /// <param name="e"></param> void TriangulateRoadAdjacentToRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) { bool hasRoadThroughEdge = cell.HasRoadThroughEdge(direction); // 扇形是否有道路 bool previousHasRiver = cell.HasRiverThroughEdge(direction.Previous()); // 上一个方向是否有河流 bool nextHasRiver = cell.HasRiverThroughEdge(direction.Next()); // 下一个方向是否有河流 Vector2 interpolators = GetRoadInterpolators(direction, cell); Vector3 roadCenter = center; // 把道路中心初始化成六边形中心 // 如果六边形是河流的源头或者尽头 if (cell.HasRiverBeginOrEnd) { // 道路中点往河流的反方向推三分之一 roadCenter += HexMetrics.GetSolidEdgeMiddle(cell.RiverBeginOrEndDirection.Opposite()) * (1f / 3f); } // 如果六边形里河流流入方向和流出方向成一直线 else if (cell.IncomingRiver == cell.OutgoingRiver.Opposite()) { Vector3 corner; // 位于河流垂线上的点 if (previousHasRiver) { // 如果扇形内没有河流且下一个方向的扇形也没有河流,则返回不进行道路三角化 if (!hasRoadThroughEdge && !cell.HasRoadThroughEdge(direction.Next())) { return; } corner = HexMetrics.GetSecondSolidCorner(direction); } else { // 如果扇形内没有河流且上一个方向的扇形也没有河流,则返回不进行道路三角化 if (!hasRoadThroughEdge && !cell.HasRoadThroughEdge(direction.Previous())) { return; } corner = HexMetrics.GetFirstSolidCorner(direction); } // 需要把道路中心两个点沿着河流的垂线往外推 roadCenter += corner * 0.5f; // 添加桥梁 if (cell.IncomingRiver == direction.Next() && // 由于有多个没有河流经过的扇形,所以只选取一个方向的扇形添加桥梁,保证只实例化一次桥梁 (cell.HasRoadThroughEdge(direction.Next2()) || cell.HasRoadThroughEdge(direction.Opposite()))) // 河流对面的扇形也有道路才添加桥梁 { features.AddBridge(roadCenter, center - corner * 0.5f); // 沿着河流垂线找到桥的第二个端点 } // 六边形中心也往外推 center += corner * 0.25f; } // 如果流入河流与流出河流相邻 else if (cell.IncomingRiver == cell.OutgoingRiver.Previous()) { // 道路中心往流入流出河流的相交尖端方向推 roadCenter -= HexMetrics.GetSecondCorner(cell.IncomingRiver) * 0.2f; } // 如果流入河流与流出河流相邻 else if (cell.IncomingRiver == cell.OutgoingRiver.Next()) { // 道路中心往流入流出河流的相交尖端方向推 roadCenter -= HexMetrics.GetFirstCorner(cell.IncomingRiver) * 0.2f; } // 如果扇形上一个方向有河流,下一个方向也有河流(流出流入河流相隔一个扇形,当前扇形位于河流弧度的内侧) else if (previousHasRiver && nextHasRiver) { // 如果扇形里没有道路,则返回不进行道路三角化 if (!hasRoadThroughEdge) { return; } Vector3 offset = HexMetrics.GetSolidEdgeMiddle(direction) * HexMetrics.innerToOuter; roadCenter += offset * 0.7f; center += offset * 0.5f; // 该参数与三角化河流那里一样用0.5,可以刚好移到河流边缘(TriangulateAdjacentToRiver方法内) } // 流出流入河流相隔一个扇形,且当前扇形位于河流弧度的外侧 else { HexDirection middle; // 中间扇形的方向 if (previousHasRiver) { middle = direction.Next(); } else if (nextHasRiver) { middle = direction.Previous(); } else { middle = direction; } // 如果河流弧度外侧三个扇形都没有河流,则不需要对道路进行三角化 if (!cell.HasRoadThroughEdge(middle) && !cell.HasRoadThroughEdge(middle.Previous()) && !cell.HasRoadThroughEdge(middle.Next())) { return; } Vector3 offset = HexMetrics.GetSolidEdgeMiddle(middle); roadCenter += offset * 0.25f; if (direction == middle && // 避免重复生成桥梁,只在创建河流弧度外侧的中间扇形道路的时候添加桥梁 cell.HasRoadThroughEdge(direction.Opposite())) // 河对岸也要有道路 { features.AddBridge(roadCenter, center - offset * (HexMetrics.innerToOuter * 0.7f)); // 这里的第二个参数为道路在河流弧度内侧时的道路中心 } } // 三角化道路 Vector3 mL = Vector3.Lerp(roadCenter, e.v1, interpolators.x); Vector3 mR = Vector3.Lerp(roadCenter, e.v5, interpolators.y); TriangulateRoad(roadCenter, mL, mR, e, hasRoadThroughEdge, cell.Index); // 如果上一个方向有河流,则三角化一个道路边缘填补空隙 if (previousHasRiver) { TriangulateRoadEdge(roadCenter, center, mL, cell.Index); } // 如果下一个方向有河流,则三角化一个道路边缘填补空隙 if (nextHasRiver) { TriangulateRoadEdge(roadCenter, mR, center, cell.Index); } }
/// <summary> /// 道路临近河流时的网格处理 /// </summary> /// <param name="direction"></param> /// <param name="cell"></param> /// <param name="center"></param> /// <param name="e"></param> void TriangulateRoadAdjacentToRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) { bool hasRoadThroughEdge = cell.HasRoadThroughEdge(direction); bool previousHasRiver = cell.HasRiverThroughEdge(direction.Previous()); bool nextHasRiver = cell.HasRiverThroughEdge(direction.Next()); Vector2 interpolators = GetRoadInterpolators(direction, cell); Vector3 roadCenter = center; // 使道路的中心向河流的反方向移动 if (cell.HasRiverBeginOrEnd) { roadCenter += HexMetrics.GetSolidEdgeMiddle( cell.RiverBeginOrEndDirection.Opposite() ) * (1f / 3f); } // 处理直线河流对于道路的分割 else if (cell.IncomingRiver == cell.OutgoingRiver.Opposite()) { Vector3 corner; if (previousHasRiver) { // 对于只有一侧有路穿越六边形一边的,将分割后的道路另一侧三角孤岛取消 if (!hasRoadThroughEdge && !cell.HasRoadThroughEdge(direction.Next())) { return; } corner = HexMetrics.GetSecondSolidCorner(direction); } else { if (!hasRoadThroughEdge && !cell.HasRoadThroughEdge(direction.Previous())) { return; } corner = HexMetrics.GetFirstSolidCorner(direction); } roadCenter += corner * 0.5f; center += corner * 0.25f; } // 对于Z字形河流的道路填充判断 else if (cell.IncomingRiver == cell.OutgoingRiver.Previous()) { // 使道路中心远离河流流入方向向量的0.2 roadCenter -= HexMetrics.GetSecondCorner(cell.IncomingRiver) * 0.2f; } else if (cell.IncomingRiver == cell.OutgoingRiver.Next()) { // 使道路中心远离河流流入方向向量的0.2 roadCenter -= HexMetrics.GetFirstCorner(cell.IncomingRiver) * 0.2f; } // 处理转弯平滑的河流的道路网格,此时是位于转弯弧内侧 else if (previousHasRiver && nextHasRiver) { // 没有道路穿过时,直接跳出方法不进行渲染 if (!hasRoadThroughEdge) { return; } Vector3 offset = HexMetrics.GetSolidEdgeMiddle(direction) * HexMetrics.innerToOuter; roadCenter += offset * 0.7f; center += offset * 0.5f; } // 处理转弯平滑的河流的道路网格,此时是位于转弯弧外侧 else { // 确定转弯弧外侧的中间方向 HexDirection middle; if (previousHasRiver) { middle = direction.Next(); } else if (nextHasRiver) { middle = direction.Previous(); } else { middle = direction; } // 如果剩余三个方向都没有道路,则跳出当前方法不生成道路 if (!cell.HasRoadThroughEdge(middle) && !cell.HasRoadThroughEdge(middle.Previous()) && !cell.HasRoadThroughEdge(middle.Next())) { return; } // 将道路弧向中间方向的边界移动25% roadCenter += HexMetrics.GetSolidEdgeMiddle(middle) * 0.25f; } Vector3 mL = Vector3.Lerp(roadCenter, e.v1, interpolators.x); Vector3 mR = Vector3.Lerp(roadCenter, e.v5, interpolators.y); TriangulateRoad(roadCenter, mL, mR, e, hasRoadThroughEdge); // 平滑处理道路与河流相遇的网格,闭合网格空隙 if (previousHasRiver) { TriangulateRoadEdge(roadCenter, center, mL); } if (nextHasRiver) { TriangulateRoadEdge(roadCenter, mR, center); } }
void Triangulate(HexCell cell, List <HexCoordinates> neighbours) { Vector3 centre = cell.transform.localPosition; List <Vector3> linePoints = new List <Vector3>(); if (cell.isHill) { Vector3 hillCentre = new Vector3(centre.x, centre.y + HexMetrics.hillHeight, centre.z); Color shadedCol = new Color(cell.colour.r * 0.8f, cell.colour.g * 0.8f, cell.colour.b * 0.8f); //Add 6 (smaller) triangles for (HexDirection d = HexDirection.NE; d <= HexDirection.NW; d++) { Vector3 firstGroundCorner = HexMetrics.GetFirstCorner(d); Vector3 secondGroundCorner = HexMetrics.GetSecondCorner(d); Vector3 firstHillCorner = HexMetrics.GetFirstHillCorner(d); Vector3 secondHillCorner = HexMetrics.GetSecondHillCorner(d); //Smaller Central Triangles AddTriangle(hillCentre, hillCentre + firstHillCorner, hillCentre + secondHillCorner); AddTriangleColour(cell.colour); linePoints.Add(hillCentre + HexMetrics.GetFirstHillCorner(d) + Vector3.up * 0.1f); //Side triangles AddTriangle(hillCentre + firstHillCorner, centre + firstGroundCorner, centre + secondGroundCorner); AddTriangle(centre + secondGroundCorner, hillCentre + secondHillCorner, hillCentre + firstHillCorner); if (d <= HexDirection.E) { AddTriangleColour(shadedCol); AddTriangleColour(shadedCol); } else { AddTriangleColour(cell.colour); AddTriangleColour(cell.colour); } //Lines up the hill LineRenderer connectorLine = Instantiate <LineRenderer>(linePrefab); connectorLine.transform.name = cell.coordinates.ToString() + " " + System.Enum.GetName(typeof(HexDirection), d) + " Line"; connectorLine.transform.parent = transform; connectorLine.positionCount = 2; connectorLine.SetPositions(new Vector3[] { hillCentre + HexMetrics.GetFirstHillCorner(d) + Vector3.up * 0.1f, centre + HexMetrics.GetFirstCorner(d) + Vector3.up * 0.1f }); } } else { //Add 6 triangles for (HexDirection d = HexDirection.NE; d <= HexDirection.NW; d++) { AddTriangle(centre, centre + HexMetrics.GetFirstCorner(d), centre + HexMetrics.GetSecondCorner(d)); AddTriangleColour(cell.colour); linePoints.Add(centre + HexMetrics.GetFirstCorner(d) + Vector3.up * 0.1f); } } LineRenderer outline = Instantiate <LineRenderer>(linePrefab); outline.transform.name = cell.coordinates.ToString() + "Outline"; outline.transform.parent = transform; outline.positionCount = 6; outline.SetPositions(linePoints.ToArray()); }
void Triangulate(HexDirection direction, HexCell cell) { bool isDeep = cell.Elevation == ElevationLevel.Deep ? true : false; Vector3 center = cell.transform.localPosition; Vector3 v1 = center + HexMetrics.GetFirstSolidCorner(direction, isDeep); Vector3 v2 = center + HexMetrics.GetSecondSolidCorner(direction, isDeep); //Center Tris terrain.AddTriangle(center, v1, v2); terrain.AddTriangleColor(cell.Color); Vector3 edge = HexMetrics.GetEdge(direction, isDeep); Vector3 tempV3 = center + HexMetrics.GetFirstEdgeCorner(direction, isDeep); Vector3 tempV4 = center + HexMetrics.GetSecondEdgeCorner(direction, isDeep); Vector3 v3 = tempV3 + edge; Vector3 v4 = tempV4 + edge; HexCell prevNeighbor = cell.GetNeighbor(direction.Previous()) ?? cell; HexCell neighbor = cell.GetNeighbor(direction) ?? cell; HexCell nextNeighbor = cell.GetNeighbor(direction.Next()) ?? cell; //Edge Elevation if (cell.Elevation < neighbor.Elevation) { v3.y = v4.y = neighbor.Position.y; } //Edge Terrace Quads & Quads if (isDeep && neighbor.Elevation == ElevationLevel.Flat) { TriangulateEdgeTerraces(v1, v2, cell, v3, v4, neighbor); } else if (isDeep && neighbor.Elevation != ElevationLevel.Flat && cell.Elevation < neighbor.Elevation) { terrain.AddQuad(v1, v2, v3, v4); terrain.AddQuadColor(neighbor.Color); } else { terrain.AddQuad(v1, v2, v3, v4); terrain.AddQuadColor(cell.Color); } Vector3 v5 = center + HexMetrics.GetFirstCorner(direction); Vector3 v6 = center + HexMetrics.GetSecondCorner(direction); //Vertice Elevation Change if (cell.Elevation < neighbor.Elevation) { v5.y = v6.y = neighbor.Position.y; } if (cell.Elevation < nextNeighbor.Elevation) { if (nextNeighbor.Elevation < neighbor.Elevation) { v6.y = neighbor.Position.y; } else { v6.y = nextNeighbor.Position.y; } } if (cell.Elevation < prevNeighbor.Elevation) { if (prevNeighbor.Elevation < neighbor.Elevation) { v5.y = neighbor.Position.y; } else { v5.y = prevNeighbor.Position.y; } } //Corner Tris & Corner Terrace Tris if (isDeep) { if (neighbor.Elevation == ElevationLevel.Flat) { TriangulateCornerTerraces(v1, cell, v5, v3, neighbor); TriangulateCornerTerraces(v2, cell, v4, v6, neighbor); } else if (cell.Elevation == neighbor.Elevation) { if (nextNeighbor.Elevation == ElevationLevel.Flat && prevNeighbor.Elevation == ElevationLevel.Flat) { TriangulateOuterCornerTerraces(v5, cell, v3, v1, prevNeighbor); TriangulateOuterCornerTerraces(v6, cell, v2, v4, nextNeighbor); } else if (nextNeighbor.Elevation == ElevationLevel.Flat) { TriangulateOuterCornerTerraces(v6, cell, v2, v4, nextNeighbor); terrain.AddTriangle(v1, v5, v3); if (cell.Elevation < prevNeighbor.Elevation) { terrain.AddTriangleColor(prevNeighbor.Color); } else { terrain.AddTriangleColor(cell.Color); } } else if (prevNeighbor.Elevation == ElevationLevel.Flat) { TriangulateOuterCornerTerraces(v5, cell, v3, v1, prevNeighbor); terrain.AddTriangle(v2, v4, v6); if (cell.Elevation < nextNeighbor.Elevation) { terrain.AddTriangleColor(nextNeighbor.Color); } else { terrain.AddTriangleColor(cell.Color); } } else if (cell.Elevation < nextNeighbor.Elevation && cell.Elevation < prevNeighbor.Elevation) { terrain.AddTriangle(v1, v5, v3); terrain.AddTriangleColor(prevNeighbor.Color); terrain.AddTriangle(v2, v4, v6); terrain.AddTriangleColor(nextNeighbor.Color); } else if (cell.Elevation < nextNeighbor.Elevation) { terrain.AddTriangle(v1, v5, v3); terrain.AddTriangleColor(cell.Color); terrain.AddTriangle(v2, v4, v6); terrain.AddTriangleColor(nextNeighbor.Color); } else if (cell.Elevation < prevNeighbor.Elevation) { terrain.AddTriangle(v1, v5, v3); terrain.AddTriangleColor(prevNeighbor.Color); terrain.AddTriangle(v2, v4, v6); terrain.AddTriangleColor(cell.Color); } else { terrain.AddTriangle(v1, v5, v3); terrain.AddTriangleColor(cell.Color); terrain.AddTriangle(v2, v4, v6); terrain.AddTriangleColor(cell.Color); } } else { if (nextNeighbor.Elevation == ElevationLevel.Flat && prevNeighbor.Elevation == ElevationLevel.Flat) { TriangulateNextCornerTerracesCliff(v6, cell, v2, v4, neighbor, nextNeighbor); TriangulatePrevCornerTerracesCliff(v5, cell, v3, v1, neighbor, prevNeighbor); } else if (nextNeighbor.Elevation == ElevationLevel.Flat) { TriangulateNextCornerTerracesCliff(v6, cell, v2, v4, neighbor, nextNeighbor); terrain.AddTriangle(v1, v5, v3); terrain.AddTriangleColor(neighbor.Color); } else if (prevNeighbor.Elevation == ElevationLevel.Flat) { TriangulatePrevCornerTerracesCliff(v5, cell, v3, v1, neighbor, prevNeighbor); terrain.AddTriangle(v2, v4, v6); terrain.AddTriangleColor(neighbor.Color); } else { terrain.AddTriangle(v1, v5, v3); terrain.AddTriangleColor(neighbor.Color); terrain.AddTriangle(v2, v4, v6); terrain.AddTriangleColor(neighbor.Color); } } } else { terrain.AddTriangle(v1, v5, v3); terrain.AddTriangleColor(cell.Color); terrain.AddTriangle(v2, v4, v6); terrain.AddTriangleColor(cell.Color); } //Features if (cell.Elevation == ElevationLevel.Flat) { features.AddFeature(cell, (center + v1 + v5) * (1f / 3f)); } }
/// <summary> /// 道路河流共存的时候 /// </summary> /// <param name="direction"></param> /// <param name="cell"></param> /// <param name="center"></param> /// <param name="e"></param> void TriangulateRoadAdjacentToRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) { bool hasRoadThroughEdge = cell.HasRoadThroughEdge(direction); bool previousHasRiver = cell.HasRiverThroughEdge(direction.Previous()); bool nextHasRiver = cell.HasRiverThroughEdge(direction.Next()); Vector2 interpolators = GetRoadInterpolators(direction, cell); Vector3 roadCenter = center; if (cell.HasRiverBeginOrEnd) { //细胞中有河流的开始或结束 //中心点道路往河流的相反方向偏移1/3位置 roadCenter += HexMetrics.GetSoliEdgeMiddle(cell.RiverBeginOrEndDirection.Opposite()) * (1f / 3f); } else if (cell.IncomingRiver == cell.OutgoingRiver.Opposite()) { //直线河流经过细胞中心 //将细胞中心的道路截成两段 Vector3 corner; if (previousHasRiver) { if (!hasRoadThroughEdge && !cell.HasRoadThroughEdge(direction.Next())) { //河流截断道路后,如果一段没有连接的道路,将返回不在绘制 //即此中心如果是道路开头或结尾 //河流截断后一遍将不绘制对应面片 return; } corner = HexMetrics.GetSecondSolidCorner(direction); } else { if (!hasRoadThroughEdge && !cell.HasRoadThroughEdge(direction.Previous())) { //河流截断道路后,如果一段没有连接的道路,将返回不在绘制 //即此中心如果是道路开头或结尾 //河流截断后一遍将不绘制对应面片 return; } corner = HexMetrics.GetFirstSolidCorner(direction); } roadCenter += corner * 0.5f; center += corner * 0.25f; } else if (cell.IncomingRiver == cell.OutgoingRiver.Previous()) { //之字型河流,即出和入河流是相邻的情况 //道路在河流汇合处偏移 roadCenter -= HexMetrics.GetSecondCorner(cell.IncomingRiver) * 0.2f; } else if (cell.IncomingRiver == cell.OutgoingRiver.Next()) { //之字型河流,即出和入河流是相邻的情况 //道路在河流汇合处偏移 roadCenter -= HexMetrics.GetFirstCorner(cell.IncomingRiver) * 0.2f; } else if (previousHasRiver && nextHasRiver) { //河流出入间隔一个单位的方向,即呈现弧形的河流,弧形内部的情况 if (!hasRoadThroughEdge) { //头尾部分,截断后多余部分返回不绘制 return; } Vector3 offset = HexMetrics.GetSoliEdgeMiddle(direction) * HexMetrics.innerToOuter; roadCenter += offset * 0.7f; center += offset * 0.5f; } else { //剩下的情况,即弧形河流的弧形外部情况 HexDirection middle; if (previousHasRiver) { middle = direction.Next(); } else if (nextHasRiver) { middle = direction.Previous(); } else { middle = direction; } if (!cell.HasRoadThroughEdge(middle) && !cell.HasRoadThroughEdge(middle.Previous()) && !cell.HasRoadThroughEdge(middle.Next())) { return; } roadCenter += HexMetrics.GetSoliEdgeMiddle(middle) * 0.25f; } Vector3 mL = Vector3.Lerp(roadCenter, e.v1, interpolators.x); Vector3 mR = Vector3.Lerp(roadCenter, e.v5, interpolators.y); TriangulateRoad(roadCenter, mL, mR, e, hasRoadThroughEdge); //填充中心位置道路偏移后的空白位置 if (previousHasRiver) { //当前方向的前一位方向存在河流时 //在道路中心、单元格中心和中间左点之间添加一个三角形 TriangulateRoadEdge(roadCenter, center, mL); //Debug.Log("Direction:" + direction); } if (nextHasRiver) { //当前方向的下一位方向存在河流时 //道路中心,中间的右点,和单元格中心之间添加一个三角形 TriangulateRoadEdge(roadCenter, mR, center); } }
void TriangulateRoadAdjacentToRiver( HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e ) { bool hasRoadThroughEdge = cell.HasRoadThroughEdge(direction); bool previousHasRiver = cell.HasRiverThroughEdge(direction.Previous()); bool nextHasRiver = cell.HasRiverThroughEdge(direction.Next()); Vector2 interpolators = GetRoadInterpolators(direction, cell); Vector3 roadCenter = center; if (cell.HasRiverBeginOrEnd) { roadCenter += HexMetrics.GetSolidEdgeMiddle( cell.RiverBeginOrEndDirection.Opposite() ) * (1f / 3f); } else if (cell.IncomingRiver == cell.OutgoingRiver.Opposite()) { Vector3 corner; if (previousHasRiver) { if ( !hasRoadThroughEdge && !cell.HasRoadThroughEdge(direction.Next()) ) { return; } corner = HexMetrics.GetSecondSolidCorner(direction); } else { if ( !hasRoadThroughEdge && !cell.HasRoadThroughEdge(direction.Previous()) ) { return; } corner = HexMetrics.GetFirstSolidCorner(direction); } roadCenter += corner * 0.5f; if (cell.IncomingRiver == direction.Next() && ( cell.HasRoadThroughEdge(direction.Next2()) || cell.HasRoadThroughEdge(direction.Opposite()) )) { features.AddBridge(roadCenter, center - corner * 0.5f); } center += corner * 0.25f; } else if (cell.IncomingRiver == cell.OutgoingRiver.Previous()) { roadCenter -= HexMetrics.GetSecondCorner(cell.IncomingRiver) * 0.2f; } else if (cell.IncomingRiver == cell.OutgoingRiver.Next()) { roadCenter -= HexMetrics.GetFirstCorner(cell.IncomingRiver) * 0.2f; } else if (previousHasRiver && nextHasRiver) { if (!hasRoadThroughEdge) { return; } Vector3 offset = HexMetrics.GetSolidEdgeMiddle(direction) * HexMetrics.innerToOuter; roadCenter += offset * 0.7f; center += offset * 0.5f; } else { HexDirection middle; if (previousHasRiver) { middle = direction.Next(); } else if (nextHasRiver) { middle = direction.Previous(); } else { middle = direction; } if ( !cell.HasRoadThroughEdge(middle) && !cell.HasRoadThroughEdge(middle.Previous()) && !cell.HasRoadThroughEdge(middle.Next()) ) { return; } Vector3 offset = HexMetrics.GetSolidEdgeMiddle(middle); roadCenter += offset * 0.25f; if ( direction == middle && cell.HasRoadThroughEdge(direction.Opposite()) ) { features.AddBridge( roadCenter, center - offset * (HexMetrics.innerToOuter * 0.7f) ); } } Vector3 mL = Vector3.Lerp(roadCenter, e.v1, interpolators.x); Vector3 mR = Vector3.Lerp(roadCenter, e.v5, interpolators.y); TriangulateRoad(roadCenter, mL, mR, e, hasRoadThroughEdge, cell.Index); if (previousHasRiver) { TriangulateRoadEdge(roadCenter, center, mL, cell.Index); } if (nextHasRiver) { TriangulateRoadEdge(roadCenter, mR, center, cell.Index); } }
private void TriangulateRoadAdjacentToRiver( HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e ) { bool hasRoadThroughEdge = cell.HasRoadThroughEdge(direction); bool previousHasRiver = cell.HasRiverThroughEdge(direction.Previous()); bool nextHasRiver = cell.HasRiverThroughEdge(direction.Next()); Vector2 interpolators = GetRoadInterpolators(direction, cell); Vector3 roadCenter = center; // Push the road center in the opposite direction of the river. This is // so that the road does not overlap with the river's begin or end. if (cell.HasRiverBeginOrEnd) { // Displace the center 1/3 of the distance to the edge middle point of the opposite direction. roadCenter += HexMetrics.GetSolidEdgeMiddle(cell.RiverBeginOrEndDirection.Opposite()) * (1f / 3f); // River crosses through the cell. } else if (cell.IncomingRiver == cell.OutgoingRiver.Opposite()) { Vector3 corner; if (previousHasRiver) { if ( !hasRoadThroughEdge && !cell.HasRoadThroughEdge(direction.Next()) ) { return; } corner = HexMetrics.GetSecondSolidCorner(direction); } else { if (!hasRoadThroughEdge && !cell.HasRoadThroughEdge(direction.Previous())) { return; } corner = HexMetrics.GetFirstSolidCorner(direction); } roadCenter += corner * 0.5f; center += corner * 0.25f; // Zig Zag cases // Move the road center by using one of the corners of the incoming river direction. // Push the road center away from that corner. } else if (cell.IncomingRiver == cell.OutgoingRiver.Previous()) { roadCenter -= HexMetrics.GetSecondCorner(cell.IncomingRiver) * 0.2f; } else if (cell.IncomingRiver == cell.OutgoingRiver.Next()) { roadCenter -= HexMetrics.GetFirstCorner(cell.IncomingRiver) * 0.2f; // Inside of Curved Rivers // River on both sides of the current direction, that means there is a curved river. In // this case pull the Road towards the current cell edge, shortening the road. } else if (previousHasRiver && nextHasRiver) { // Prune isolated road parts, that is, do not render a road through that edge. if (!hasRoadThroughEdge) { return; } Vector3 offset = HexMetrics.GetSolidEdgeMiddle(direction) * HexMetrics.innerToOuter; roadCenter += offset * 0.7f; center += offset * 0.5f; // Outside of a curving river // There are three cell parts on the outside, we have to // find the middle direction. } else { HexDirection middle; if (previousHasRiver) { middle = direction.Next(); } else if (nextHasRiver) { middle = direction.Previous(); } else { middle = direction; } // Prune this side of the river if there is no road that continues through // this direction, the previous or the next one. if (!cell.HasRoadThroughEdge(middle) && !cell.HasRoadThroughEdge(middle.Previous()) && !cell.HasRoadThroughEdge(middle.Next())) { return; } roadCenter += HexMetrics.GetSolidEdgeMiddle(middle) * 0.25f; } Vector3 mL = Vector3.Lerp(roadCenter, e.v1, interpolators.x); Vector3 mR = Vector3.Lerp(roadCenter, e.v5, interpolators.y); TriangulateRoad(roadCenter, mL, mR, e, hasRoadThroughEdge); if (previousHasRiver) { TriangulateRoadEdge(roadCenter, center, mL); } if (nextHasRiver) { TriangulateRoadEdge(roadCenter, mR, center); } }