前言
断断续续的在catlikecoding.com上学习,一路到了Hexmap系列,决定从此开始记录一下学习心得。也在网上看到了很多大牛的翻译,大都是整篇整篇的翻译,而且纸上得来终觉浅,在此想把此系列教程,逐步分小篇幅边学习边记录学习过程中的心得
Hexmap系列最基础的开始就是画一个正六边形,因此作为系列学习入门,先从用Mesh画一个(仅仅是一个)正六边形说起
正六边形特性
如上图正六边形,有一下特性:
- 六条边长都相等,设边长为L
- 中心连接六个顶点,组成六个等边三角形
- 外接圆(图中蓝色圆)半径,也就是outerRadius等于六边形边长
。
- 内切圆(图中红色虚线圆)半径,也就是innerRadius,根据简单的三角勾股定理求得等于
.
正六边形顶点坐标
如图以正六边形顶点为原点,建立局部坐标系,因为最终六边形画在XZ平面,所以红色对应为unityX轴,蓝色为Z轴。Y轴坐标为0。坐标轴原点为V0,六个顶点顺时针分别命名为V1,V2,V3,V4,V5,V6。
则在此坐标系下,根据简单的计算(也就是直角三角形勾股定理这些)可以计算出每个顶点的坐标,如下:
//正六边形外接圆半径,等于正六边形边长
public const float outerRadius = 20;
//正六边形内切圆半径,等于sqrt(3)*outerRaidus/2,其中sqrt(3)/2 = 0.866025404f
public const float innerRadius = outerRadius * 0.866025404f;
private Vector3[] corners =
{
new Vector3(0,0,outerRadius),//V1
new Vector3(innerRadius,0,0.5f*outerRadius),//V2
new Vector3(innerRadius,0,-0.5f*outerRadius),//V3
new Vector3(0,0,-outerRadius),//V4
new Vector3(-innerRadius,0,-0.5f*outerRadius),//V5
new Vector3(-innerRadius,0,0.5f*outerRadius),//V6
};
开始画一个正六边形
创建一个MonoBehaviour脚本,命名为Hexgon,定义Mesh变量,和mesh需要的顶点和三角形数据信息
Mesh HexagonMesh;
private List<Vector3> vertices = new List<Vector3>();
private List<int> triangles = new List<int>();
在Awake里完成相关初始化
private void Awake()
{
GameObject MeshSpwan = new GameObject("MeshSpwan");
MeshSpwan.AddComponent<MeshFilter>();
MeshSpwan.AddComponent<MeshRenderer>();
HexagonMesh = MeshSpwan.GetComponent<MeshFilter>().mesh;
HexagonMesh.Clear();
}
对于自定义Mesh,如果想要画出想要的图形,需要计算出该mesh的顶点数据(也就是mesh里面的vertices数据)和mesh中对应的三角形数据(也就是顶点索引)
private void Triangulate()
{
//循环画出每一个三角形
for (int i = 0; i < 6; i++)
{
AddRriangle(Vector3.zero, corners[i], corners[i + 1]);
}
}
private void AddRriangle(Vector3 v1,Vector3 v2,Vector3 v3)
{
int verterIndex = vertices.Count;
//三角形1顶点数据(V0,V1,V2)
//三角形2顶点数据(V0,V2,V3)
//三角形3顶点数据(V0,V3,V4)
//三角形4顶点数据(V0,V4,V5)
//三角形5顶点数据(V0,V5,V6)
//三角形3顶点数据(V0,V6,V1)
vertices.Add(v1);
vertices.Add(v2);
vertices.Add(v3);
//第一个三角形对应的triangles索引在verterices的索引是(0,1,2)
//第而个三角形对应的triangles索引在verterices的索引是(3,4,5)
///...
triangles.Add(verterIndex);
triangles.Add(verterIndex + 1);
triangles.Add(verterIndex + 2);
}
最终代码为
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Hexagon : MonoBehaviour
{
Mesh HexagonMesh;
private List<Vector3> vertices = new List<Vector3>();
private List<int> triangles = new List<int>();
//正六边形外接圆半径,等于正六边形边长
public const float outerRadius = 20;
//正六边形内切圆半径,等于sqrt(3)*outerRaidus/2,其中sqrt(3)/2 = 0.866025404f
public const float innerRadius = outerRadius * 0.866025404f;
private Vector3[] corners =
{
new Vector3(0,0,outerRadius),//V1
new Vector3(innerRadius,0,0.5f*outerRadius),//V2
new Vector3(innerRadius,0,-0.5f*outerRadius),//V3
new Vector3(0,0,-outerRadius),//V4
new Vector3(-innerRadius,0,-0.5f*outerRadius),//V5
new Vector3(-innerRadius,0,0.5f*outerRadius),//V6
new Vector3(0,0,outerRadius),//V1。形成一个闭环,组织mesh三角形数据的时候需要
};
private void Awake()
{
GameObject MeshSpwan = new GameObject("MeshSpwan");
MeshSpwan.AddComponent<MeshFilter>();
MeshSpwan.AddComponent<MeshRenderer>();
HexagonMesh = MeshSpwan.GetComponent<MeshFilter>().mesh;
HexagonMesh.Clear();
}
private void Start()
{
Triangulate();
HexagonMesh.vertices = vertices.ToArray();
HexagonMesh.triangles = triangles.ToArray();
}
private void Triangulate()
{
//循环画出每一个三角形
for (int i = 0; i < 6; i++)
{
AddRriangle(Vector3.zero, corners[i], corners[i + 1]);
}
}
private void AddRriangle(Vector3 v1,Vector3 v2,Vector3 v3)
{
int verterIndex = vertices.Count;
//三角形1顶点数据(V0,V1,V2)
//三角形2顶点数据(V0,V2,V3)
//三角形3顶点数据(V0,V3,V4)
//三角形4顶点数据(V0,V4,V5)
//三角形5顶点数据(V0,V5,V6)
//三角形3顶点数据(V0,V6,V1)
vertices.Add(v1);
vertices.Add(v2);
vertices.Add(v3);
//第一个三角形对应的triangles索引在verterices的索引是(0,1,2)
//第而个三角形对应的triangles索引在verterices的索引是(3,4,5)
///...
triangles.Add(verterIndex);
triangles.Add(verterIndex + 1);
triangles.Add(verterIndex + 2);
}
}
最后运行得出一个正六边形