在上一章中,我们完成了河流的起点或终点在地图单元中的构建。结合之前笔直穿过地图单元的河流,我们现在已经可以在地图上画出不拐弯的河流并正确的显示出来了。但是我们发现,如果一条河流经过地图单元的时候,方向发生了变化,那么河流的视觉效果就产生了错误。如下图所示:
这里,我们将河流在一个地图单元上的流入口和流出口,在两个相邻边上的情况,叫做一折河道
,另外一种情况,就是流出口和流入口中间相隔一条边的情况,叫做二折河道
。在本章中,我们来实现如何正确的构建一折河道的三角面片。
我们回到HexMesh.TriangulateWithRiver
方法中,在这里进行判断,如果河流是笔直穿过地图单元,那么就使用现有的方式进行构建。否则依然将中位线上的5个顶点平均分布在其上,使得河道呈现向地图单元中心点聚拢的效果。代码如下:
HexMesh.cs1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| private void TriangulateWithRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) { Vector3 centerL, centerR; if (cell.HasRiverThroughEdge(direction.Opposite())) { centerL = center + HexMetrics.GetFirstSolidCorner(direction.Previous()) * 0.25f; centerR = center + HexMetrics.GetSecondSolidCorner(direction.Next()) * 0.25f; } else { centerL = centerR = center; } … }
|
接着,我们判断当前河道的两个相邻边,是否有其他河道,这样我们就知道当前穿过地图单元的河道是否为一折河道了。代码如下:
HexMesh.cs1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| private void TriangulateWithRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) { if (cell.HasRiverThroughEdge(direction.Opposite())) { centerL = center + HexMetrics.GetFirstSolidCorner(direction.Previous()) * 0.25f; centerR = center + HexMetrics.GetSecondSolidCorner(direction.Next()) * 0.25f; } else if (cell.HasRiverThroughEdge(direction.Next())) { centerL = center; centerR = Vector3.Lerp(center, e.v5, 0.5f); } else if (cell.HasRiverThroughEdge(direction.Previous())) { centerL = Vector3.Lerp(center, e.v1, 0.5f); centerR = center; } else { centerL = centerR = center; } … }
|
在确认了河道两侧端点位置之后,我们可以通过偏移中心点的位置,使其偏离河道的中心一些,让河道在转弯处看起来没那么狭窄。代码如下:
HexMesh.cs1 2 3 4 5 6 7 8 9 10 11 12
| private void TriangulateWithRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) { if (cell.HasRiverThroughEdge(direction.Opposite())) { … }
…
center = Vector3.Lerp(centerL, centerR, 0.5f); }
|
在观察运行结果之后,我们发现虽然河道宽度在转弯的时候没有改变,但还是有一种河道被挤压了的感觉。这是应为河道因为转弯,中心线形成了一个60度的夹角,内侧看起来就像变窄了一样。在这里我们将弯道内侧的顶点偏移量减小,使得内侧的空间变大,来避免出现这种挤压感。代码如下:
HexMesh.cs1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| private void TriangulateWithRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) { … else if (cell.HasRiverThroughEdge(direction.Next())) { centerL = center; centerR = Vector3.Lerp(center, e.v5, 2f / 3f); } else if (cell.HasRiverThroughEdge(direction.Previous())) { centerL = Vector3.Lerp(center, e.v1, 2f / 3f); centerR = center; } … }
|
至此,我们就完成了一折河道的构建,并优化了其在视觉上产生的一些挤压感,让河道看起来更加自然。在下一章中,我们将分析并完成二折河道的构建。
Github代码