1-5 绘制正六边形地图单元
在上一章中,我们已经排列好了每个地图单元的位置,但是每个地图单元的外观还是正方形的;这一章中,会将正方形的外观更换成正六边形的外观。
要将正方形地图元素外观替换为正六边形地图元素外观,这里首先删除Hex Cell预置上,除了Hex Cell
脚本以外的所有组件,如下图:
接下来,创建HexMesh脚本,内容如下:
1 | using UnityEngine; |
脚本创建完成后,在Hex Grid物体下创建一个子物体,命名为Hex Mesh,并挂载HexMesh
脚本。因为HexMesh
脚本中有[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
语句,所以在Hex Mesh物体上会自动创建MeshFilter组件和MeshRenderer组件,但是MeshRenderer组件中没有默认的材质球,这里为其添加Unity自带的默认材质球,完成效果如下图:
接下来,回到HexGrid
脚本中,在其Awake方法中,与取得Canvas组件相类似,可以取得HexMesh组件。代码如下:
1 | //存储Hex Mesh物体上的hexMesh脚本组件 |
获取到HexMesh组件实例后,就可以调用其中的方法来构建正六边形的三角面片了,但是这里要注意,生成三角面片的方法调用,必须在HexMesh
脚本初始化完成之后,所以这里在HexGrid
的Start方法中调用构建三角面的方法,代码如下:
1 | private void Start() |
其实HexMesh.Triangulate
方法在程序的任何阶段都可以被调用。在之后的一些步骤中,运行时对地图作出调整,我们还会调用这个方法,所以,在这个方法中,首先要清空旧的mesh、vertices、triangles这些变量的内容;接着读取存储所有HexCell实例的数组,依次录入其顶点Vector3信息和顶点顺序索引;然后将所有HexCell的这些信息全都保存在hexMesh的vertices和triangles数组中;最后,调用RecalculateNormals方法重新计算法线,使最后生成的三角面的视觉效果正确。HexMesh
脚本修改代码如下:
1 | /// <summary> |
由于正六边形是由多个三角面片构成的,所以需要创建AddTriangle
方法,这个方法入参为3个顶点的Vector3信息。将3个入参信息添加到vertices链表中,并且与其对应的索引值添加到triangles链表中,以备Triangulate
方法利用两个链表统一生成三角面片,修改代码如下:
1 | /// <summary> |
现在,生成每个地图单元中三角面片的方法基本完成了,在正式生成之前,我们需要
先完善Triangulate(HexCell cell)
方法,首先测试生成每个正六边形地图元素的第一个三角面片,即从顶部第一个顶点开始计算的两个顶点和中点共同构成的三角面。代码如下:
1 | /// <summary> |
这样,就为每个正六边形地图元素,生成了第一个三角面片。效果如下图:
通过观察上图可以得出,只要修改private void Triangulate(HexCell cell)
方法内调用AddTriangle
方法的部分,循环6次,即可生成全部的三角面片,修改代码如下:
1 | //根据中点位置计算出其余的顶点位置信息 |
在完成以上代码后,如果直接运行,Unity会弹出一个索引越界的错误,导致这个错误的原因是,当for循环中的i为6时,center + HexMetrics.corners[i + 1]中括号里的值为7,而HexMetrics.corners数组中只存储了6个顶点信息HexMetrics.corners[7]其实就是第一个顶点,即正六边形最上方的顶点,所以这里需要在corners数组的末尾添加一条数据,使HexMetrics.corners[7]指向第一个顶点的位置。代码如下:
1 | //正六边形的六个顶点位置,其姿态为角朝上,从最上面一个顶点开始计算位置 |
在corners数组中添加完数据后,运行效果如下图:
最后还有一点需要讨论,为什么我们不合并重叠的顶点?
其实完全可以合并,并且还能将“面数”进行优化,比如只使用4个三角形面片就可以拼接成一个正六边形,而不是6个,但是在之后的步骤中,还会对正六边形地图元素作出一些其他的改动,如果现在优化顶点和面数,可能会导致之后的步骤变得更加复杂和难以处理。
这一章我们已经生成了正确的正六边形地图元素,下一章将会重新排列这些地图元素的坐标,为之后的计算便捷做准备。