6-16 一折河道的构建

  在上一章中,我们完成了河流的起点或终点在地图单元中的构建。结合之前笔直穿过地图单元的河流,我们现在已经可以在地图上画出不拐弯的河流并正确的显示出来了。但是我们发现,如果一条河流经过地图单元的时候,方向发生了变化,那么河流的视觉效果就产生了错误。如下图所示:

  这里,我们将河流在一个地图单元上的流入口和流出口,在两个相邻边上的情况,叫做一折河道,另外一种情况,就是流出口和流入口中间相隔一条边的情况,叫做二折河道。在本章中,我们来实现如何正确的构建一折河道的三角面片。
  我们回到HexMesh.TriangulateWithRiver方法中,在这里进行判断,如果河流是笔直穿过地图单元,那么就使用现有的方式进行构建。否则依然将中位线上的5个顶点平均分布在其上,使得河道呈现向地图单元中心点聚拢的效果。代码如下:

HexMesh.cs
1
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;
//这里将河道情况分开讨论了
//1 笔直穿过cell的河道
//2 出入口相邻的河道
//3 出入口间隔一条边的河道
if (cell.HasRiverThroughEdge(direction.Opposite()))//先判断是否是笔直穿过
{
centerL = center + HexMetrics.GetFirstSolidCorner(direction.Previous()) * 0.25f;
centerR = center + HexMetrics.GetSecondSolidCorner(direction.Next()) * 0.25f;
}
else
{
//如果不是笔直的河道,就将河流端点聚拢在cell中心
centerL = centerR = center;
}


}

  接着,我们判断当前河道的两个相邻边,是否有其他河道,这样我们就知道当前穿过地图单元的河道是否为一折河道了。代码如下:

HexMesh.cs
1
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.cs
1
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()))
{

}



//重新计算cell中心点的位置,让其偏离河道弯折处,这样河道在转弯的地方就不会显得狭窄了
center = Vector3.Lerp(centerL, centerR, 0.5f);
}

  在观察运行结果之后,我们发现虽然河道宽度在转弯的时候没有改变,但还是有一种河道被挤压了的感觉。这是应为河道因为转弯,中心线形成了一个60度的夹角,内侧看起来就像变窄了一样。在这里我们将弯道内侧的顶点偏移量减小,使得内侧的空间变大,来避免出现这种挤压感。代码如下:

HexMesh.cs
1
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代码