1-1 关于Hexmap

  地图系统是一个回合制策略游戏的基础,一个灵活、稳固、拓展性强的地图系统会给游戏带来更多的可能。

  在传统日式回合制策略RPG游戏中,大多使用了正方形元素来构建地图系统。正方形元素有绘制简单、三角面数较少、计算相对简单等优势,但是也具有一些先天性的劣势,下图为一个正方形地图单元,以及围绕其周围的8个地图单元。

  通过观察发现,水平和垂直相邻的地图单元,两者中点的距离为正方形单元边长,也就是绿色箭头表示的距离。

  而斜向位置的相邻地图单元,两者中点的距离为正方形单元边长的 $\sqrt 2$ 倍,也就是红色箭头表示的距离。

  由于相邻的地图单元之间有两种不同的距离,这种差异化的距离在实际游戏中会比较难处理。所以,有些游戏中,只会选择在地图单元的水平和垂直方向移动,从而避免距离差异化带来的问题。但是,这样在一定程度上减少了游戏的多样性与可玩性。

  为了解决距离差异化问题,并且同时保持游戏玩法的灵活与多样性,使用了正六边形地图单元来代替正方形地图单元。

  与正方形单元相比,正六边形单元有6个相邻单元。并且,两个单元中点之间的距离是相等的,不存在距离之间的差异化。这样就既消除了距离差异的问题,同时还保持了游戏的多样性和可玩性。

  在正式开始编码之前,还需要对正六边形单元做一些简单的设定。这里设定每个正六边形单元的边长为10。如下图所示:

  由正六边形的几何特点可知,如果正六边形的边长为10,其外接圆的半径也为10(蓝色实线线表示),其内切圆半径是边长的 $\frac {\sqrt 3} 2$(证明过程),也就是 $5 \sqrt3$(红色虚线表示)。

  基础的设定完成后,接下来就可以在Unity中创建脚本开始编码了。首先创建HexMetrics.cs脚本,声明2个常量,outerRadiusinnerRadius,表示正六边形的外接圆和内切圆半径。代码如下:

HexMetrics.cs
1
2
3
4
5
6
7
8
9
10
using UnityEngine;

public static class HexMetrics
{
//正六边形的边长 同时也是正六边形外接圆的半径
public const float outerRadius = 10f;

//正六边形的内切圆半径,长度为外接圆的 二分之根号三倍
public const float innerRadius = outerRadius * 0.866025404f;
}

  脚本创建完成后,让我们来继续观察一下正六边形单元。在正六边形排列的形式有两种,一类是边朝上,一类是角朝上。为了方便之后的计算,我们选择角朝上的排列类型。如下图所示:

  在HexMetrics类中添加如下代码,通过正六边形的中点、外接圆半径、内切圆半径定义正六边形的六个顶点

exMetrics.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using UnityEngine;

public static class HexMetrics
{
//正六边形的边长 同时也是正六边形外接圆的半径
public const float outerRadius = 10f;

//正六边形的内切圆半径,长度为外接圆的 二分之根号三倍
public const float innerRadius = outerRadius * 0.866025404f;

//正六边形的六个顶点位置,其姿态为角朝上,从最上面一个顶点开始计算位置
//根据正六边形中点的位置,顺时针依次定义6个顶点的位置
public static Vector3[] corners =
{
new Vector3(0f, 0f, outerRadius),
new Vector3(innerRadius, 0f, 0.5f * outerRadius),
new Vector3(innerRadius, 0f, -0.5f * outerRadius),
new Vector3(0f, 0f, -outerRadius),
new Vector3(-innerRadius, 0f, -0.5f * outerRadius),
new Vector3(-innerRadius, 0f, 0.5f * outerRadius)
};
}

  这样,基本的地图单元就创建完成了,下一步,要创建一个二维数组,来存放实例化到场景中的地图单元,并且记录每个地图单元在该数组中的位置。

Github代码