3-6 阶梯状的连接区域

  在之前的章节中我们修复了地图单元对应UI高度和连接区域断裂的问题。同时我们也发现一个问题,在两个相邻且有高差的地图单元之间,连接区域只是被简单的拉伸了。如果高差很大的话,这个现象就更加明显。在接下来的章节中,我们来丰富连接区域的细节。
  增加连接区域的具体方式,我们可以参考《无尽传奇》这个游戏。将一个倾斜的连接区域插入两段阶梯,如下图所示。这样一个完整的斜面就被分为了三个小斜面。每个斜面之间用平面相连接。这就需要我们把这个阶梯斜面分为五个部分来看。

  我们回到HexMetrics.cs中,在这里定义每个连接面中需要插入阶梯的数量,并由此计算出整个连接区域会被拆分成几个部分。

HexMetrics.cs
1
2
3
4
5
6
7
8
9
10
11
12
public static class HexMetrics
{
//每个连接部分阶梯的数量
public const int terracesPerSlope = 2;

//横向步长个数
//根据阶梯数量,计算出连接区域会被拆分成几个横向步长
//参考图 http://magi-melchiorl.gitee.io/pages/Pics/Hexmap/3-6-1.png
public const int terraceSteps = terracesPerSlope * 2 + 1;


}

  接下来我们需要计算被拆分出来连接区域中每个部分的顶点的位置。通过观察上图我们发现,如果设左下角的顶点为阶梯的起始点,也就是第0步,那么在Y坐标有变化的顶点,都是奇数步上的顶点。按照这个规律就可以得到一个梯田状的连接区域了。在HexMetrics.cs中添加一个特殊的插值方法来实现这个功能。

HexMetrics.cs
1
2
3
4
5
6
7
8
9
10
11
/// <summary>
/// 通过插值计算出阶梯状连接区域,每个顶点的坐标位置
/// </summary>
/// <param name="a">起始顶点的位置</param>
/// <param name="b">结束顶点的位置</param>
/// <param name="step">第几个步长</param>
/// <returns>根据步长插值计算得出的顶点的位置</returns>
public static Vector3 TerraceLerp(Vector3 a, Vector3 b, int step)
{
return a;
}

  通过观察上图我们还发现,每个顶点的插值分为两部分,一个是垂直方向的,一个是水平方向的。这里先通过步长计算出每个顶点的水平坐标。

HexCell.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
//横向每个步长占整体长度的比例
public const float horizontalTerraceStepSize = 1f / terraceSteps;

public static Vector3 TerraceLerp(Vector3 a, Vector3 b, int step)
{
//单个步长的比例 与 步长的个数,计算出现在顶点所在的比例
float h = step * horizontalTerraceStepSize;

//水平位置的X和Z,分别乘以 现在顶点所在的比例,得出该步长顶点的实际坐标
a.x += (b.x - a.x) * h;
a.z += (b.z - a.z) * h;
return a;
}

两个值之间的插值是怎么计算的?
两个值$ a $$ b $之间的插值,需要第三个插入值$ t $。当$ t $为0时,结果就是$ a $。当$ t $为1时,结果就是$ b $。当$ t $为0到1之间的某个值时,结果为$ a $$ b $之间的某个值。所以插值公式为$ (1-t)a+tb $。这个公式可以变成$ (1-t)a+tb=a-ta+tb=a+t(b-a) $。其中$ t $的值相当于向量$ b-a $$ a $$ b $移动的距离。这样简化之后,所需要的乘法计算步骤更少。

  接下来我们要设置步长中每个顶点的的Y坐标。因为只有在奇数步长的时候,Y坐标才会改变,所以这里使用$ \frac{step+1}{2} $来计算。这里只取商的整数部分,相当于把序列1, 2, 3, 4变成了1, 1, 2, 2

HexCell.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//纵向每个步长占整体长度的比例
public const float verticalTerraceStepSize = 1f / (terracesPerSlope + 1);

public static Vector3 TerraceLerp(Vector3 a, Vector3 b, int step)
{


//参考图 http://magi-melchiorl.gitee.io/pages/Pics/Hexmap/3-6-1.png
//根据参考图可以知道,实时位置点位步长0,那么只有在奇数步长时候才会改变Y坐标
//(step + 1) / 2取商的整数部分,其实就是将步长1 2 3 4,变成了1 1 2 2这种形式
//也就是只在奇数步长的时候对Y值进行改变
float v = ((step + 1) / 2) * HexMetrics.verticalTerraceStepSize;

//计算出Y的插值之后,计算出实际Y的坐标值
a.y += (b.y - a.y) * v;

return a;
}

  每个步长顶点的坐标计算完成后,我们还需要计算每个步长顶点的颜色值。这里相较于计算坐标更加简单。每个顶点的颜色值,只需要根据水平位置的插值来计算就可以了。

HexCell.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/// <summary>
/// 通过插值计算出集体装连接区域,每个顶点的颜色值
/// 计算颜色值不需要考虑垂直方向坐标变化的问题,只需要根据水平插值便可以得出计算结果
/// </summary>
/// <param name="a">起始顶点的位置</param>
/// <param name="b">结束顶点的位置</param>
/// <param name="step">第几个步长</param>
/// <returns></returns>
public static Color TerraceLerp(Color a, Color b, int step)
{
//单个步长的比例 与 步长的个数,计算出现在顶点所在的比例
float h = step * horizontalTerraceStepSize;

//通过Color.Lerp方法,计算出现在顶点的颜色值
return Color.Lerp(a, b, h);
}

  这样,我们就完成了计算阶梯连接区域中,每个步长顶点的位置、颜色的功能了。在下面的章节中,我们将调用这些方法来实现矩形连接区域的三角构建。

[Github代码](