從零開始做一個SLG遊戲(一):六邊形網格
本文的主要工作是六邊形網格的繪製。
如圖所示。六邊形有6個方向,6個頂點,同時定義中心點到邊的最短距離為內徑innerRadius,定義中心點到頂點的距離為外徑outerRadius。
六邊形可以拆分為6個等邊三角形,所以很容易得出:
定義遊戲中六邊形的邊長(即外徑)為10.
用一個靜態類以及一個列舉將這些定義下來:
- using UnityEngine;
- public static class HexMetrics
- {
- /// <summary>
- /// 外徑,中心到頂點距離
- /// </summary>
- public const float outerRadius = 10f;
- /// <summary>
- /// 內徑,中心到邊距離,0.866025404為二分之根號三的近似值
- /// </summary>
- public const float innerRadius = outerRadius * 0.866025404f;
-
- /// <summary>
- /// 六邊形的六個頂點座標
- /// </summary>
- public static readonly 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)
- };
- }
- /// <summary>
- /// 六邊形的方向
- /// NW /\ NE
- /// W | |E
- /// SW \/ SE
- /// </summary>
- public enum HexDirection
- {
- NE,
- E,
- SE,
- SW,
- W,
- NW,
- }
之後開始寫關於圖片繪製的程式碼:
將六邊形分解為6個等邊三角形,三角形的三個頂點分別為六邊形中心點,以及六邊形一條邊的兩個頂點:
即HexMetrics.corners和HexMetrics.corners[i+1]
因為第六條邊的時候,i=5,i+1=6,corners[6]不存在,所以在定義里加一個coners[6],和coners[0]相等:
- public static readonly 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),
- new Vector3(0f,0f,outerRadius),
- };
所以繪製三角形的時候,程式碼可以寫成這樣:
- /// <summary>
- /// 繪製地形
- /// </summary>
- public void Draw()
- {
- Clear();
- Vector3 center = Vector3.zero;
- for (HexDirection dir = HexDirection.NE; dir <= HexDirection.NW; dir++)
- {
- AddTriangle(center,
- HexMetrics.corners[(int)dir],
- HexMetrics.corners[(int)dir + 1]);
- }
- UpdateMesh();
- }
然後貼上全部程式碼:
- [RequireComponent(typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshCollider))]
- public class HexCell : MonoBehaviour {
- private Mesh mesh;
- private List<Vector3> vertices;
- private List<int> triangles;
- private void Awake()
- {
- GetComponent<MeshFilter>().mesh = mesh = GetComponent<MeshCollider>().sharedMesh = new Mesh();
- GetComponent<MeshCollider>().convex = true;
- mesh.name = "Hex Cell";
- vertices = new List<Vector3>();
- triangles = new List<int>();
- Draw();
- }
- // Use this for initialization
- void Start () {
-
- }
-
- // Update is called once per frame
- void Update () {
-
- }
- /// <summary>
- /// 繪製地形
- /// </summary>
- public void Draw()
- {
- Clear();
- Vector3 center = Vector3.zero;
- for (HexDirection dir = HexDirection.NE; dir <= HexDirection.NW; dir++)
- {
- AddTriangle(center,
- HexMetrics.corners[(int)dir],
- HexMetrics.corners[(int)dir + 1]);
- }
- UpdateMesh();
- }
- /// <summary>
- /// 清空mesh資料
- /// </summary>
- private void Clear()
- {
- mesh.Clear();
- vertices.Clear();
- triangles.Clear();
- }
- /// <summary>
- /// 繪製mesh資料
- /// </summary>
- private void UpdateMesh()
- {
- mesh.vertices = vertices.ToArray();
- mesh.triangles = triangles.ToArray();
- mesh.RecalculateNormals();
- mesh.RecalculateBounds();
- }
- /// <summary>
- /// 新增三角形。
- /// </summary>
- /// <param name="v1"></param>
- /// <param name="v2"></param>
- /// <param name="v3"></param>
- private void AddTriangle(Vector3 v1, Vector3 v2, Vector3 v3)
- {
- int count = triangles.Count;
- vertices.Add(v1);
- triangles.Add(count++);
- vertices.Add(v2);
- triangles.Add(count++);
- vertices.Add(v3);
- triangles.Add(count++);
- }
- }
在unity中新建一個空的物體,掛上這個指令碼,然後隨便扔一個材質上去,執行就會出現如下圖片:
接下來就是構建地圖網格:
如圖,仔細觀察我們就可以我們可以發現:
1.同一行的相鄰六邊形的間距為2個內徑的距離
2.兩列六邊形,在縱座標上相差1.5個外徑的距離
3.列數為奇數的六邊形在橫座標上,會向右偏移1個內徑的距離。
所以我們可以通過如下方式將佇列上的座標(x,y)轉換為空間上的座標:
- private Vector3 GetPos(int x, int y)
- {
- float posX = x;
- float posY = y;
- if ((y & 1) != 0)
- {
- posX += 0.5f;
- }
- Vector3 pos = new Vector3(2f * posX * HexMetrics.innerRadius, 0f, 1.5f * posY * HexMetrics.outerRadius);
- return pos;
- }
為了便於區分,再將網格的顏色變一下:
- cell.GetComponent<MeshRenderer>().material.color = new Color(posX / width, (posX + posY) / (height + width), posY / height);
一個六邊形的網格地圖的雛形就做好了,執行一下,我們就可以得到下面圖片:
參考文章:
Hex Map 1
當初也是因為這篇文章,才萌生了做六邊形SLG遊戲的念頭的
作者:觀復
專欄地址:https://zhuanlan.zhihu.com/p/44306412
相關文章
- 從零開始做一個SLG遊戲(三):用unity繪製圖形遊戲Unity
- 從零開始做一個SLG遊戲(六):UI系統擴充套件遊戲UI套件
- 從零開始做一個SLG遊戲(七):遊戲系統以及配置表遊戲
- 從零開始做一個SLG遊戲(八):配置表載入元件遊戲元件
- 從零開始做一個SLG遊戲(四):UI系統之主介面搭建遊戲UI
- 從零開始做一個SLG遊戲(五):UI系統之彈窗功能遊戲UI
- 從零開始做一個SLG遊戲(二):用mesh實現簡單的地形遊戲
- 從零開始:用REACT寫一個格鬥遊戲(一)React遊戲
- 從零開始:用REACT寫一個格鬥遊戲(二)React遊戲
- 從零開始搭建一個 hexo 部落格。Hexo
- 從零開始設計一個部落格
- 從零開始實現放置遊戲(一)遊戲
- HexMap學習筆記(一)——建立六邊形網格筆記
- 想找人一起從零開始擼一個部落格
- 從0開始用python寫一個命令列小遊戲(六)Python命令列遊戲
- 從零點五開始用Unity做半個2D戰棋小遊戲(一)Unity遊戲
- 從零開始寫一個ExporterExport
- 從零開始開發一個 WebpackWeb
- 邊學邊做的第一個Unity小遊戲Unity遊戲
- 如何利用CSS寫一個六邊形?CSS
- H5 六邊形消除遊戲開發H5遊戲開發
- 從零開始實現放置遊戲(六):Excel批量匯入遊戲Excel
- 【從零開始擼一個App】PKCEAPP
- 【從零開始擼一個App】KotlinAPPKotlin
- 從零開始實現一個RPC框架(零)RPC框架
- 從零開始寫一個node爬蟲(一)爬蟲
- 從零開始實現一個RPC框架(一)RPC框架
- 從零開始實現放置遊戲(一):整體框架搭建遊戲框架
- phaser3入門教程-從零開始開發一個打磚塊遊戲遊戲
- 從零開始仿寫一個抖音App——開始APP
- 從零開始完成一個Android JNI開發Android
- 從零開始搭建一個mock服務Mock
- 從零開始搭建一個vue專案Vue
- 從零開始學typescript構建一個rest風格web服務TypeScriptRESTWeb
- 從零開始實現一個RPC框架(四)RPC框架
- 從零開始實現一個RPC框架(二)RPC框架
- 從零開始編寫一個babel外掛Babel
- 從零開始實現一個RPC框架(五)RPC框架